tunit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +113 -0
- data/Rakefile +9 -0
- data/example_spec.rb +35 -0
- data/example_test.rb +23 -0
- data/lib/tunit.rb +83 -0
- data/lib/tunit/assertion_errors.rb +43 -0
- data/lib/tunit/assertions.rb +68 -0
- data/lib/tunit/autorun.rb +8 -0
- data/lib/tunit/compound_reporter.rb +33 -0
- data/lib/tunit/hooks.rb +11 -0
- data/lib/tunit/progress_reporter.rb +11 -0
- data/lib/tunit/reporter.rb +39 -0
- data/lib/tunit/runnable.rb +51 -0
- data/lib/tunit/spec.rb +77 -0
- data/lib/tunit/summary_reporter.rb +50 -0
- data/lib/tunit/test.rb +104 -0
- data/lib/tunit/version.rb +3 -0
- data/test/rtest_test.rb +19 -0
- data/test/tunit/assertion_errors_test.rb +95 -0
- data/test/tunit/assertions_test.rb +68 -0
- data/test/tunit/progress_reporter_test.rb +45 -0
- data/test/tunit/reporter_test.rb +66 -0
- data/test/tunit/runnable_test.rb +69 -0
- data/test/tunit/spec_test.rb +57 -0
- data/test/tunit/summary_reporter_test.rb +116 -0
- data/test/tunit/test_case.rb +72 -0
- data/test/tunit/test_test.rb +181 -0
- data/tunit.gemspec +24 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5769b36f6ff1b870f97abe003b76ec180c387e17
|
4
|
+
data.tar.gz: 6c35816f53a6e5e5b3e1f310482338e7f263ff79
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9aeb067328c6d07e694215c0b77794a78645e4e49f71a806e9d13a0713be5b300f0585472fa893d410a6133862ba5724da8bac2f1116358bd9fff171567d37d1
|
7
|
+
data.tar.gz: 7b6754bb52f757ccfe7d1a2bb344f7fee592d2a29da47dbe896a8113b6e21a028380c050ea4fb7da851914946c6367111fcaa45abd83e964d5b11f14c93a73c4
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Teo Ljungberg
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# Tunit
|
2
|
+
|
3
|
+
`tunit` is my take on building a testing framework, it's heavily influenced by
|
4
|
+
[minitest](https://github.com/seattlerb/minitest).
|
5
|
+
|
6
|
+
|
7
|
+
_NOTE_ This is very unstable and is just a playground for my ideas.
|
8
|
+
|
9
|
+
## Credit
|
10
|
+
Since this is heavily influenced by
|
11
|
+
[Ryan Davis](https://twitter.com/the_zenspider)' minitest there are a lot of
|
12
|
+
similarities between the two frameworks.
|
13
|
+
|
14
|
+
I wanted to see how much code and effort are needed to build a testing
|
15
|
+
framework of my own, while looking at the learnings of minitest.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
### Unit
|
19
|
+
|
20
|
+
I personally _love_ TDD frameworks like minitest, so I tried to mimic their
|
21
|
+
behaviour and patterns as close as I possibly could. As with minitest, this is
|
22
|
+
just plain ruby.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class BlahTest < Tunit::Test
|
26
|
+
def setup
|
27
|
+
self.blah = Blah.new
|
28
|
+
end
|
29
|
+
attr_accessor :blah
|
30
|
+
|
31
|
+
def test_the_answer_to_everything
|
32
|
+
assert_equal 42, blah.the_ultimate_answer
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_packing_list
|
36
|
+
assert_includes blah.packing_list, "towel"
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_that_will_be_skipped
|
40
|
+
skip "test this later"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
What's important to me is that `BlahTest` is just a simple subclass, and
|
46
|
+
`test_the_answer_to_everything` is a simple method. Assertions and
|
47
|
+
lazily-loaded variables are just methods, everything is just a simple method
|
48
|
+
definition away.
|
49
|
+
|
50
|
+
I'm a strong believer in that you should only mock and stub things so you can
|
51
|
+
assert on something else. That's why a `test`-method must have assertions in
|
52
|
+
`tunit`
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class EmptyTest < Tunit::Test
|
56
|
+
def test_im_going_to_fail
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_so_will_i
|
60
|
+
1 + 1 == 2
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
### Spec
|
66
|
+
There is also a small Spec DSL that follows along with tunit
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
require 'tunit/autorun'
|
70
|
+
|
71
|
+
Example = Class.new
|
72
|
+
|
73
|
+
describe Example do
|
74
|
+
describe 'passing tests' do
|
75
|
+
it 'even' do
|
76
|
+
assert 2.even?
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'passed once more' do
|
80
|
+
assert_includes [1, 2], 2
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'failing tests' do
|
85
|
+
it 'fails on empty tests' do
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'fails hard' do
|
89
|
+
refute 2.even?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'skipps' do
|
94
|
+
it 'skippedy skip' do
|
95
|
+
skip
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'skips with a message' do
|
99
|
+
skip 'here!'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
That's it, no magic let's or subjects. Just `it` and `describe` blocks
|
106
|
+
|
107
|
+
## Contributing
|
108
|
+
|
109
|
+
1. Fork it ( http://github.com/teoljungberg/tunit/fork )
|
110
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
111
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
112
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
113
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/example_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
require 'tunit/autorun'
|
3
|
+
|
4
|
+
Example = Class.new
|
5
|
+
|
6
|
+
describe Example do
|
7
|
+
describe 'passing tests' do
|
8
|
+
it 'even' do
|
9
|
+
assert 2.even?
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'passed once more' do
|
13
|
+
assert_includes [1, 2], 2
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'failing tests' do
|
18
|
+
it 'fails on empty tests' do
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'fails hard' do
|
22
|
+
refute 2.even?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'skipps' do
|
27
|
+
it 'skippedy skip' do
|
28
|
+
skip
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'skips with a message' do
|
32
|
+
skip 'here!'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/example_test.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:<< File.join(File.dirname(__FILE__), 'lib')
|
2
|
+
require 'tunit/autorun'
|
3
|
+
|
4
|
+
class ExampleTest < Tunit::Test
|
5
|
+
def test_pass
|
6
|
+
assert 2.even?
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_pass_one_more
|
10
|
+
assert_includes [1, 2], 2
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_empty
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_skip
|
17
|
+
skip
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_skip_with_message
|
21
|
+
skip 'here!'
|
22
|
+
end
|
23
|
+
end
|
data/lib/tunit.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "tunit/compound_reporter"
|
2
|
+
require "tunit/summary_reporter"
|
3
|
+
require "tunit/progress_reporter"
|
4
|
+
require "tunit/test"
|
5
|
+
require "tunit/version"
|
6
|
+
|
7
|
+
require 'optparse'
|
8
|
+
|
9
|
+
module Tunit
|
10
|
+
meta_klass = (class << self; self; end)
|
11
|
+
meta_klass.send :attr_accessor, :reporter
|
12
|
+
|
13
|
+
# Let io be override-able in tests
|
14
|
+
meta_klass.send :attr_accessor, :io
|
15
|
+
self.io = $stdout
|
16
|
+
|
17
|
+
# Make sure that autorun is loaded after each test class has been loaded
|
18
|
+
meta_klass.send :attr_accessor, :installed_at_exit
|
19
|
+
self.installed_at_exit ||= false
|
20
|
+
|
21
|
+
def self.autorun
|
22
|
+
at_exit {
|
23
|
+
next if $! and not ($!.kind_of? SystemExit and $!.success?)
|
24
|
+
|
25
|
+
exit_code = nil
|
26
|
+
|
27
|
+
at_exit {
|
28
|
+
exit exit_code || false
|
29
|
+
}
|
30
|
+
|
31
|
+
exit_code = Tunit.run ARGV
|
32
|
+
} unless self.installed_at_exit
|
33
|
+
self.installed_at_exit = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.run args = []
|
37
|
+
options = process_args! args
|
38
|
+
|
39
|
+
self.reporter = CompoundReporter.new
|
40
|
+
reporter << SummaryReporter.new(options[:io], options)
|
41
|
+
reporter << ProgressReporter.new(options[:io], options)
|
42
|
+
|
43
|
+
reporter.start
|
44
|
+
dispatch! reporter, options
|
45
|
+
reporter.report
|
46
|
+
|
47
|
+
reporter.passed?
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def self.dispatch! reporter, options
|
53
|
+
Runnable.runnables.each do |runnable|
|
54
|
+
runnable.run reporter, options
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.process_args! args = []
|
59
|
+
options = { io: io }
|
60
|
+
|
61
|
+
OptionParser.new do |opts|
|
62
|
+
opts.banner = "Tunit options:"
|
63
|
+
opts.version = Tunit::VERSION
|
64
|
+
|
65
|
+
opts.on "-h", "--help", "Display this help." do
|
66
|
+
puts opts
|
67
|
+
exit
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.on "-n", "--name PATTERN", "Filter run on /pattern/ or string." do |pattern|
|
71
|
+
options[:filter] = pattern
|
72
|
+
end
|
73
|
+
|
74
|
+
opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
|
75
|
+
options[:verbose] = true
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.parse! args
|
79
|
+
end
|
80
|
+
|
81
|
+
options
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Tunit
|
2
|
+
class Assertion < Exception
|
3
|
+
def error
|
4
|
+
self
|
5
|
+
end
|
6
|
+
|
7
|
+
def location
|
8
|
+
last_before_assertion = ""
|
9
|
+
self.backtrace.reverse_each do |line|
|
10
|
+
break if line =~ /in .(assert|refute|pass|raise)/
|
11
|
+
last_before_assertion = line
|
12
|
+
end
|
13
|
+
last_before_assertion.sub(/:in .*$/, "")
|
14
|
+
end
|
15
|
+
|
16
|
+
def result_code
|
17
|
+
result_label[0, 1]
|
18
|
+
end
|
19
|
+
|
20
|
+
def result_label
|
21
|
+
"Failure"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Empty < Assertion
|
26
|
+
# Where was the empty test
|
27
|
+
attr_accessor :location
|
28
|
+
|
29
|
+
def result_code
|
30
|
+
"_"
|
31
|
+
end
|
32
|
+
|
33
|
+
def result_label
|
34
|
+
"Empty"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Skip < Assertion
|
39
|
+
def result_label
|
40
|
+
"Skipped"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'tunit/assertion_errors'
|
2
|
+
|
3
|
+
module Tunit
|
4
|
+
module Assertions
|
5
|
+
def skip msg = nil, bt = caller
|
6
|
+
method_responsible = bt[0][/`.*'/][1..-2]
|
7
|
+
msg ||= "Skipped '#{method_responsible}'"
|
8
|
+
fail ::Tunit::Skip, msg, bt
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert test, msg = nil
|
12
|
+
msg ||= "Failed assertion, no message given."
|
13
|
+
self.assertions += 1
|
14
|
+
unless test
|
15
|
+
msg = msg.call if Proc === msg
|
16
|
+
fail ::Tunit::Assertion, msg
|
17
|
+
end
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def assert_equal exp, act, msg = nil
|
22
|
+
msg ||= "Failed assertion, no message given."
|
23
|
+
assert exp == act, msg
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_includes collection, obj, msg = nil
|
27
|
+
msg ||= "Expected #{collection.inspect} to include #{obj}"
|
28
|
+
assert_respond_to collection, :include?
|
29
|
+
assert collection.include?(obj), msg
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_respond_to obj, meth, msg = nil
|
33
|
+
msg ||= "Expected #{obj.inspect} (#{obj.class}) to respond to ##{meth}"
|
34
|
+
assert obj.respond_to?(meth), msg
|
35
|
+
end
|
36
|
+
|
37
|
+
def assert_instance_of klass, obj, msg = nil
|
38
|
+
msg ||= "Expected #{obj.inspect} to be an instance of #{klass}, not #{obj.class}"
|
39
|
+
assert obj.instance_of?(klass), msg
|
40
|
+
end
|
41
|
+
|
42
|
+
def refute test, msg = nil
|
43
|
+
msg ||= "Failed assertion, no message given."
|
44
|
+
! assert !test, msg
|
45
|
+
end
|
46
|
+
|
47
|
+
def refute_equal exp, act, msg = nil
|
48
|
+
msg ||= "Failed assertion, no message given."
|
49
|
+
refute exp == act, msg
|
50
|
+
end
|
51
|
+
|
52
|
+
def refute_includes collection, obj, msg = nil
|
53
|
+
msg ||= "Expected #{collection.inspect} to not include #{obj}"
|
54
|
+
assert_respond_to collection, :include?
|
55
|
+
refute collection.include?(obj), msg
|
56
|
+
end
|
57
|
+
|
58
|
+
def refute_respond_to obj, meth, msg = nil
|
59
|
+
msg ||= "Expected #{obj.inspect} (#{obj.class}) to not respond to #{meth}"
|
60
|
+
refute obj.respond_to?(meth), msg
|
61
|
+
end
|
62
|
+
|
63
|
+
def refute_instance_of klass, obj, msg = nil
|
64
|
+
msg ||= "Expected #{obj.inspect} not to be an instance of #{klass}"
|
65
|
+
refute obj.instance_of?(klass), msg
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|