Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbaddaden committed Feb 25, 2015
0 parents commit cd68685
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.crystal
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Test Unit

An attempt at implementing test units in Crystal, using the fantastic
[minitest](https://github.com/seattlerb/minitest) as reference.

```crystal
require "minitest/autorun"
class MyTest < Minitest::Test
def setup
@var = "something"
end
def teardown
@var = nil
end
def test_something
p @var # => "something"
end
end
```

## TODO

- [x] keep a list of classes inheriting Minitest::Test (test suites)
- [x] shuffle test suites
- [x] run all test suites at exit
- [x] extract the list of test methods from test suites
- [ ] shuffle test methods
- [x] run the test methods
- [x] run setup / teardown methods before/after each test
- [x] capture exceptions in setup, test or teardown
- [ ] after run hooks
- [ ] assertions
- [ ] refutations
- [ ] skip
- [ ] flunk
- [ ] reporter: composite (dispatches to linked reporters)
- [ ] reporter: progress
- [ ] reporter: verbose progress
- [ ] reporter: summary

## Requirements

This requires Crystal >= 0.6.1.
15 changes: 15 additions & 0 deletions src/minitest.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require "./minitest/reporter"
require "./minitest/runnable"
require "./minitest/test"

module Minitest
macro def self.run : Bool

This comment has been minimized.

Copy link
@ysbaddaden

ysbaddaden Feb 27, 2015

Author Owner

@asterite there is no reason for this def to be a macro anymore (since the bug was fixed in crystal), but if I make it a plain method, then @type.methods in Runnable#run_tests will only contain Runnable methods instead of the inherited class methods.

It looks like with a def macro here, then #run_tests will be generated on the inherited classes (as expected), but without the def macro it will be associated to Runnable only (not expected, at least for me).

The joys of metaprogramming :-)

This comment has been minimized.

Copy link
@asterite

asterite Feb 27, 2015

Contributor

Thanks for letting me know. It's a bug for sure. I'll investigate :-)

This comment has been minimized.

Copy link
@asterite

asterite Feb 27, 2015

Contributor

I found the problem, and it has to do with the way macro defs are currently handled in the compiler. With this code there's no way the current way can work, and I wanted to improve it for some time now, so here's my chance :-)

I'll let you know when I do this (if I can!)

This comment has been minimized.

Copy link
@asterite

asterite Feb 27, 2015

Contributor

Well, I found another way to solve the problem, much easier, as you can see by the length of the commit:

crystal-lang/crystal@2f7d39e

I changed the macro def in your minitest to just def and it still works, yay! :-)

This comment has been minimized.

Copy link
@ysbaddaden

ysbaddaden Feb 28, 2015

Author Owner

😄

reporter = Reporter.new
reporter.start

Runnable.runnables.shuffle.each(&.run)

reporter.report
reporter.passed?
end
end
7 changes: 7 additions & 0 deletions src/minitest/assertions.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Minitest
class Assertion < Exception
end

module Assertions
end
end
10 changes: 10 additions & 0 deletions src/minitest/autorun.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "../minitest"

def exit(code : Bool)
exit code ? 0 : -1
end

at_exit do
exit_code = Minitest.run
exit exit_code
end
13 changes: 13 additions & 0 deletions src/minitest/reporter.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Minitest
class Reporter
def start
end

def report
end

def passed?
false
end
end
end
23 changes: 23 additions & 0 deletions src/minitest/runnable.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Minitest
class Runnable
@@runnables = [Runnable]

This comment has been minimized.

Copy link
@asterite

asterite Feb 27, 2015

Contributor

Here you can do @@runnables = [] of Runnable.class

This comment has been minimized.

Copy link
@ysbaddaden

ysbaddaden Feb 27, 2015

Author Owner

Thanks! That one is tricky. I expected Runnable:Class for example.

@@runnables.clear

def self.runnables
@@runnables
end

macro inherited
Minitest::Runnable.runnables << self
end

macro def self.run : Nil
klass = {{ (@class_name.ends_with?(":Class") ? @class_name[0..-7].id : @class_name).id }}
klass.new.run_tests
nil
end

def run_tests
end
end
end
70 changes: 70 additions & 0 deletions src/minitest/test.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require "./assertions"

module Minitest
module LifecycleHooks
def before_setup
end

def setup
end

def after_setup
end

def before_teardown
end

def teardown
end

def after_teardown
end
end

class UnexpectedError < Exception
getter :exception

def initialize(@exception)
super "Unexpected error: #{exception}"
end
end

class Test < Runnable
include LifecycleHooks
include Assertions

# TODO: shuffle test methods
macro def run_tests : Nil
{{ @type.methods.map(&.name.stringify).select(&.starts_with?("test_")).map { |m| "run_one { #{m.id} }" }.join("\n").id }}
nil
end

def run_one
capture_exception do
before_setup
setup
after_setup

yield
end

capture_exception { before_teardown }
capture_exception { teardown }
capture_exception { after_teardown }
end

def capture_exception
begin
yield
rescue ex : Assertion
self.class.failures << ex
rescue ex : Exception
self.class.failures << UnexpectedError.new(ex)
end
end

def self.failures
@@failures ||= [] of Assertion | UnexpectedError
end
end
end
26 changes: 26 additions & 0 deletions test/runnables_test.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require "../src/minitest/autorun"

class RunnableTest < Minitest::Test
def setup
puts "custom setup"
@myvar = "instance_val"
end

def teardown
puts "\n"
end

def test_something
puts "something"
puts "@var = #{@myvar}"
end

def test_something_else
puts "else"
puts helper
end

def helper
"help me"
end
end

0 comments on commit cd68685

Please sign in to comment.