test-unit 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +24 -1
- data/Manifest.txt +8 -0
- data/README.txt +1 -0
- data/Rakefile +1 -2
- data/html/github-logo.png +0 -0
- data/html/index.html +30 -19
- data/html/index.html.ja +29 -17
- data/html/test-unit.css +9 -2
- data/lib/test/unit/assertions.rb +77 -19
- data/lib/test/unit/attribute.rb +33 -29
- data/lib/test/unit/autorunner.rb +15 -1
- data/lib/test/unit/collector/xml.rb +250 -0
- data/lib/test/unit/data.rb +80 -0
- data/lib/test/unit/error.rb +4 -3
- data/lib/test/unit/fixture.rb +30 -1
- data/lib/test/unit/runner/xml.rb +15 -0
- data/lib/test/unit/testcase.rb +201 -85
- data/lib/test/unit/testresult.rb +6 -2
- data/lib/test/unit/testsuite.rb +17 -1
- data/lib/test/unit/testsuitecreator.rb +79 -0
- data/lib/test/unit/ui/console/testrunner.rb +23 -20
- data/lib/test/unit/ui/testrunnermediator.rb +11 -2
- data/lib/test/unit/ui/xml/testrunner.rb +224 -0
- data/lib/test/unit/version.rb +1 -1
- data/test/fixtures/plus.csv +3 -0
- data/test/test-data.rb +179 -0
- data/test/test-fixture.rb +163 -0
- data/test/test-testcase.rb +49 -29
- data/test/test_testsuite.rb +19 -11
- metadata +14 -6
data/lib/test/unit/testresult.rb
CHANGED
@@ -31,8 +31,10 @@ module Test
|
|
31
31
|
include TestResultOmissionSupport
|
32
32
|
include TestResultNotificationSupport
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
FINISHED = name + "::FINISHED"
|
35
|
+
CHANGED = name + "::CHANGED"
|
36
|
+
PASS_ASSERTION = name + "::PASS_ASSERTION"
|
37
|
+
FAULT = name + "::FAULT"
|
36
38
|
|
37
39
|
attr_reader :run_count, :pass_count, :assertion_count, :faults
|
38
40
|
|
@@ -48,6 +50,7 @@ module Test
|
|
48
50
|
# Records a test run.
|
49
51
|
def add_run
|
50
52
|
@run_count += 1
|
53
|
+
notify_listeners(FINISHED, self)
|
51
54
|
notify_changed
|
52
55
|
end
|
53
56
|
|
@@ -58,6 +61,7 @@ module Test
|
|
58
61
|
# Records an individual assertion.
|
59
62
|
def add_assertion
|
60
63
|
@assertion_count += 1
|
64
|
+
notify_listeners(PASS_ASSERTION, self)
|
61
65
|
notify_changed
|
62
66
|
end
|
63
67
|
|
data/lib/test/unit/testsuite.rb
CHANGED
@@ -18,14 +18,16 @@ module Test
|
|
18
18
|
# has a suite method as simply providing a way to get a
|
19
19
|
# meaningful TestSuite instance.
|
20
20
|
class TestSuite
|
21
|
-
attr_reader :name, :tests
|
21
|
+
attr_reader :name, :tests, :test_case, :start_time, :elapsed_time
|
22
22
|
|
23
23
|
# Test suite that has higher priority is ran prior to
|
24
24
|
# test suites that have lower priority.
|
25
25
|
attr_accessor :priority
|
26
26
|
|
27
27
|
STARTED = name + "::STARTED"
|
28
|
+
STARTED_OBJECT = name + "::STARTED::OBJECT"
|
28
29
|
FINISHED = name + "::FINISHED"
|
30
|
+
FINISHED_OBJECT = name + "::FINISHED::OBJECT"
|
29
31
|
|
30
32
|
# Creates a new TestSuite with the given name.
|
31
33
|
def initialize(name="Unnamed TestSuite", test_case=nil)
|
@@ -34,19 +36,28 @@ module Test
|
|
34
36
|
@test_case = test_case
|
35
37
|
@n_tests = 0
|
36
38
|
@priority = 0
|
39
|
+
@start_time = nil
|
40
|
+
@elapsed_time = nil
|
41
|
+
@passed = true
|
37
42
|
end
|
38
43
|
|
39
44
|
# Runs the tests and/or suites contained in this
|
40
45
|
# TestSuite.
|
41
46
|
def run(result, &progress_block)
|
47
|
+
@start_time = Time.now
|
42
48
|
yield(STARTED, name)
|
49
|
+
yield(STARTED_OBJECT, self)
|
43
50
|
run_startup(result)
|
44
51
|
while test = @tests.shift
|
45
52
|
@n_tests += test.size
|
46
53
|
test.run(result, &progress_block)
|
54
|
+
@passed = false unless test.passed?
|
47
55
|
end
|
48
56
|
run_shutdown(result)
|
57
|
+
ensure
|
58
|
+
@elapsed_time = Time.now - @start_time
|
49
59
|
yield(FINISHED, name)
|
60
|
+
yield(FINISHED_OBJECT, self)
|
50
61
|
end
|
51
62
|
|
52
63
|
# Adds the test to the suite.
|
@@ -85,6 +96,10 @@ module Test
|
|
85
96
|
@tests == other.tests
|
86
97
|
end
|
87
98
|
|
99
|
+
def passed?
|
100
|
+
@passed
|
101
|
+
end
|
102
|
+
|
88
103
|
private
|
89
104
|
def run_startup(result)
|
90
105
|
return if @test_case.nil? or !@test_case.respond_to?(:startup)
|
@@ -110,6 +125,7 @@ module Test
|
|
110
125
|
false
|
111
126
|
else
|
112
127
|
result.add_error(Error.new(@test_case.name, exception))
|
128
|
+
@passed = false
|
113
129
|
true
|
114
130
|
end
|
115
131
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Kouhei Sutou
|
4
|
+
# Copyright::
|
5
|
+
# * Copyright (c) 2011 Kouhei Sutou <tt><kou@clear-code.com></tt>
|
6
|
+
# License:: Ruby license.
|
7
|
+
|
8
|
+
module Test
|
9
|
+
module Unit
|
10
|
+
class TestSuiteCreator # :nodoc:
|
11
|
+
def initialize(test_case)
|
12
|
+
@test_case = test_case
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
suite = TestSuite.new(@test_case.name, @test_case)
|
17
|
+
collect_test_names.each do |test_name|
|
18
|
+
data_sets = @test_case.attributes(test_name)[:data]
|
19
|
+
if data_sets
|
20
|
+
data_sets.each do |data_set|
|
21
|
+
data_set = data_set.call if data_set.respond_to?(:call)
|
22
|
+
data_set.each do |label, data|
|
23
|
+
append_test(suite, test_name) do |test|
|
24
|
+
test.assign_test_data(label, data)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
append_test(suite, test_name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
append_test(suite, "default_test") if suite.empty?
|
33
|
+
suite
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def append_test(suite, test_name)
|
38
|
+
test = @test_case.new(test_name)
|
39
|
+
yield(test) if block_given?
|
40
|
+
suite << test if test.valid?
|
41
|
+
end
|
42
|
+
|
43
|
+
def collect_test_names
|
44
|
+
method_names = @test_case.public_instance_methods(true).collect do |name|
|
45
|
+
name.to_s
|
46
|
+
end
|
47
|
+
test_names = method_names.find_all do |method_name|
|
48
|
+
method_name =~ /^test./ or @test_case.attributes(method_name)[:test]
|
49
|
+
end
|
50
|
+
send("sort_test_names_in_#{@test_case.test_order}_order", test_names)
|
51
|
+
end
|
52
|
+
|
53
|
+
def sort_test_names_in_alphabetic_order(test_names)
|
54
|
+
test_names.sort
|
55
|
+
end
|
56
|
+
|
57
|
+
def sort_test_names_in_random_order(test_names)
|
58
|
+
test_names.sort_by {rand(test_names.size)}
|
59
|
+
end
|
60
|
+
|
61
|
+
def sort_test_names_in_defined_order(test_names)
|
62
|
+
added_methods = @test_case.added_methods
|
63
|
+
test_names.sort do |test1, test2|
|
64
|
+
test1_defined_order = added_methods.index(test1)
|
65
|
+
test2_defined_order = added_methods.index(test2)
|
66
|
+
if test1_defined_order and test2_defined_order
|
67
|
+
test1_defined_order <=> test2_defined_order
|
68
|
+
elsif test1_defined_order
|
69
|
+
1
|
70
|
+
elsif test2_defined_order
|
71
|
+
-1
|
72
|
+
else
|
73
|
+
test1 <=> test2
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -56,13 +56,20 @@ module Test
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def attach_to_mediator
|
59
|
-
@mediator.add_listener(TestResult::FAULT,
|
60
|
-
|
61
|
-
@mediator.add_listener(TestRunnerMediator::
|
62
|
-
|
63
|
-
@mediator.add_listener(
|
64
|
-
|
65
|
-
@mediator.add_listener(
|
59
|
+
@mediator.add_listener(TestResult::FAULT,
|
60
|
+
&method(:add_fault))
|
61
|
+
@mediator.add_listener(TestRunnerMediator::STARTED,
|
62
|
+
&method(:started))
|
63
|
+
@mediator.add_listener(TestRunnerMediator::FINISHED,
|
64
|
+
&method(:finished))
|
65
|
+
@mediator.add_listener(TestCase::STARTED_OBJECT,
|
66
|
+
&method(:test_started))
|
67
|
+
@mediator.add_listener(TestCase::FINISHED_OBJECT,
|
68
|
+
&method(:test_finished))
|
69
|
+
@mediator.add_listener(TestSuite::STARTED_OBJECT,
|
70
|
+
&method(:test_suite_started))
|
71
|
+
@mediator.add_listener(TestSuite::FINISHED_OBJECT,
|
72
|
+
&method(:test_suite_finished))
|
66
73
|
end
|
67
74
|
|
68
75
|
def add_fault(fault)
|
@@ -191,10 +198,10 @@ module Test
|
|
191
198
|
fault.long_display
|
192
199
|
end
|
193
200
|
|
194
|
-
def test_started(
|
201
|
+
def test_started(test)
|
195
202
|
return unless output?(VERBOSE)
|
196
203
|
|
197
|
-
name = name.sub(/\(.+?\)\z/, '')
|
204
|
+
name = test.name.sub(/\(.+?\)\z/, '')
|
198
205
|
right_space = 8 * 2
|
199
206
|
left_space = @progress_row_max - right_space
|
200
207
|
left_space = left_space - indent.size - name.size
|
@@ -203,7 +210,7 @@ module Test
|
|
203
210
|
@test_start = Time.now
|
204
211
|
end
|
205
212
|
|
206
|
-
def test_finished(
|
213
|
+
def test_finished(test)
|
207
214
|
unless @already_outputted
|
208
215
|
output_progress(".", color("pass"))
|
209
216
|
end
|
@@ -214,24 +221,24 @@ module Test
|
|
214
221
|
output(": (%f)" % (Time.now - @test_start), nil, VERBOSE)
|
215
222
|
end
|
216
223
|
|
217
|
-
def test_suite_started(
|
224
|
+
def test_suite_started(suite)
|
218
225
|
if @top_level
|
219
226
|
@top_level = false
|
220
227
|
return
|
221
228
|
end
|
222
229
|
|
223
230
|
output_single(indent, nil, VERBOSE)
|
224
|
-
if
|
225
|
-
_color = color("case")
|
226
|
-
else
|
231
|
+
if suite.test_case.nil?
|
227
232
|
_color = color("suite")
|
233
|
+
else
|
234
|
+
_color = color("case")
|
228
235
|
end
|
229
|
-
output_single(name, _color, VERBOSE)
|
236
|
+
output_single(suite.name, _color, VERBOSE)
|
230
237
|
output(": ", nil, VERBOSE)
|
231
238
|
@indent += 2
|
232
239
|
end
|
233
240
|
|
234
|
-
def test_suite_finished(
|
241
|
+
def test_suite_finished(suite)
|
235
242
|
@indent -= 2
|
236
243
|
end
|
237
244
|
|
@@ -458,7 +465,3 @@ module Test
|
|
458
465
|
end
|
459
466
|
end
|
460
467
|
end
|
461
|
-
|
462
|
-
if __FILE__ == $0
|
463
|
-
Test::Unit::UI::Console::TestRunner.start_command_line_test
|
464
|
-
end
|
@@ -33,9 +33,15 @@ module Test
|
|
33
33
|
Unit.run = true
|
34
34
|
|
35
35
|
result = create_result
|
36
|
-
|
36
|
+
finished_listener = result.add_listener(TestResult::FINISHED) do |*args|
|
37
|
+
notify_listeners(TestResult::FINISHED, *args)
|
38
|
+
end
|
39
|
+
changed_listener = result.add_listener(TestResult::CHANGED) do |*args|
|
37
40
|
notify_listeners(TestResult::CHANGED, *args)
|
38
41
|
end
|
42
|
+
pass_assertion_listener = result.add_listener(TestResult::PASS_ASSERTION) do |*args|
|
43
|
+
notify_listeners(TestResult::PASS_ASSERTION, *args)
|
44
|
+
end
|
39
45
|
fault_listener = result.add_listener(TestResult::FAULT) do |*args|
|
40
46
|
notify_listeners(TestResult::FAULT, *args)
|
41
47
|
end
|
@@ -51,7 +57,10 @@ module Test
|
|
51
57
|
ensure
|
52
58
|
elapsed_time = Time.now - start_time
|
53
59
|
result.remove_listener(TestResult::FAULT, fault_listener)
|
54
|
-
result.remove_listener(TestResult::CHANGED,
|
60
|
+
result.remove_listener(TestResult::CHANGED, changed_listener)
|
61
|
+
result.remove_listener(TestResult::FINISHED, finished_listener)
|
62
|
+
result.remove_listener(TestResult::PASS_ASSERTION,
|
63
|
+
pass_assertion_listener)
|
55
64
|
notify_listeners(FINISHED, elapsed_time)
|
56
65
|
end
|
57
66
|
|
@@ -0,0 +1,224 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Author:: Kouhei Sutou
|
4
|
+
# Copyright::
|
5
|
+
# * Copyright (c) 2011 Kouhei Sutou <kou@clear-code.com>
|
6
|
+
# License:: Ruby license.
|
7
|
+
|
8
|
+
require 'erb'
|
9
|
+
require 'time'
|
10
|
+
require 'test/unit/ui/testrunner'
|
11
|
+
require 'test/unit/ui/testrunnermediator'
|
12
|
+
|
13
|
+
module Test
|
14
|
+
module Unit
|
15
|
+
module UI
|
16
|
+
module XML
|
17
|
+
|
18
|
+
# Runs a Test::Unit::TestSuite and outputs XML.
|
19
|
+
class TestRunner < UI::TestRunner
|
20
|
+
include ERB::Util
|
21
|
+
|
22
|
+
# Creates a new TestRunner for running the passed
|
23
|
+
# suite. :output option specifies where runner
|
24
|
+
# output should go to; defaults to STDOUT.
|
25
|
+
def initialize(suite, options={})
|
26
|
+
super
|
27
|
+
@output = @options[:output] || STDOUT
|
28
|
+
if @options[:output_file_descriptor]
|
29
|
+
@output = IO.new(@options[:output_file_descriptor], "w")
|
30
|
+
end
|
31
|
+
@already_outputted = false
|
32
|
+
@indent = 0
|
33
|
+
@top_level = true
|
34
|
+
@current_test = nil
|
35
|
+
@current_test_suite = nil
|
36
|
+
@already_outputted = false
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def attach_to_mediator
|
41
|
+
@mediator.add_listener(TestResult::PASS_ASSERTION,
|
42
|
+
&method(:result_pass_assertion))
|
43
|
+
@mediator.add_listener(TestResult::FAULT,
|
44
|
+
&method(:result_fault))
|
45
|
+
@mediator.add_listener(TestRunnerMediator::STARTED,
|
46
|
+
&method(:started))
|
47
|
+
@mediator.add_listener(TestRunnerMediator::FINISHED,
|
48
|
+
&method(:finished))
|
49
|
+
@mediator.add_listener(TestCase::STARTED_OBJECT,
|
50
|
+
&method(:test_started))
|
51
|
+
@mediator.add_listener(TestCase::FINISHED_OBJECT,
|
52
|
+
&method(:test_finished))
|
53
|
+
@mediator.add_listener(TestSuite::STARTED_OBJECT,
|
54
|
+
&method(:test_suite_started))
|
55
|
+
@mediator.add_listener(TestSuite::FINISHED_OBJECT,
|
56
|
+
&method(:test_suite_finished))
|
57
|
+
end
|
58
|
+
|
59
|
+
def result_pass_assertion(result)
|
60
|
+
open_tag("pass-assertion") do
|
61
|
+
output_test(@current_test)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def result_fault(fault)
|
66
|
+
open_tag("test-result") do
|
67
|
+
open_tag("result") do
|
68
|
+
output_test_suite(@current_test_suite)
|
69
|
+
output_test(@current_test)
|
70
|
+
open_tag("backtrace") do
|
71
|
+
fault.location.each do |entry|
|
72
|
+
file, line, info = entry.split(/:/, 3)
|
73
|
+
open_tag("entry") do
|
74
|
+
add_content("file", file)
|
75
|
+
add_content("line", line)
|
76
|
+
add_content("info", info)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
if fault.respond_to?(:expected)
|
81
|
+
add_content("expected", fault.expected)
|
82
|
+
end
|
83
|
+
if fault.respond_to?(:actual)
|
84
|
+
add_content("actual", fault.actual)
|
85
|
+
end
|
86
|
+
add_content("detail", fault.message)
|
87
|
+
add_content("status", fault.label.downcase)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@already_outputted = true if fault.critical?
|
91
|
+
end
|
92
|
+
|
93
|
+
def started(result)
|
94
|
+
@result = result
|
95
|
+
output_started
|
96
|
+
end
|
97
|
+
|
98
|
+
def output_started
|
99
|
+
open_tag("stream")
|
100
|
+
end
|
101
|
+
|
102
|
+
def finished(elapsed_time)
|
103
|
+
add_content("success", @result.passed?)
|
104
|
+
close_tag("stream")
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_started(test)
|
108
|
+
@already_outputted = false
|
109
|
+
@current_test = test
|
110
|
+
open_tag("start-test") do
|
111
|
+
output_test(test)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_finished(test)
|
116
|
+
unless @already_outputted
|
117
|
+
open_tag("test-result") do
|
118
|
+
output_test(test)
|
119
|
+
open_tag("result") do
|
120
|
+
output_test_suite(@current_test_suite)
|
121
|
+
output_test(test)
|
122
|
+
add_content("status", "success")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
open_tag("complete-test") do
|
128
|
+
output_test(test)
|
129
|
+
add_content("success", test.passed?)
|
130
|
+
end
|
131
|
+
@current_test = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_suite_started(suite)
|
135
|
+
@current_test_suite = suite
|
136
|
+
if suite.test_case.nil?
|
137
|
+
open_tag("ready-test-suite") do
|
138
|
+
add_content("n-tests", suite.size)
|
139
|
+
end
|
140
|
+
open_tag("start-test-suite") do
|
141
|
+
output_test_suite(suite)
|
142
|
+
end
|
143
|
+
else
|
144
|
+
open_tag("ready-test-case") do
|
145
|
+
output_test_suite(suite)
|
146
|
+
add_content("n-tests", suite.size)
|
147
|
+
end
|
148
|
+
open_tag("start-test-case") do
|
149
|
+
output_test_suite(suite)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_suite_finished(suite)
|
155
|
+
if suite.test_case.nil?
|
156
|
+
open_tag("complete-test-suite") do
|
157
|
+
output_test_suite(suite)
|
158
|
+
add_content("success", suite.passed?)
|
159
|
+
end
|
160
|
+
else
|
161
|
+
open_tag("complete-test-case") do
|
162
|
+
output_test_suite(suite)
|
163
|
+
add_content("success", suite.passed?)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
@current_test_suite = nil
|
167
|
+
end
|
168
|
+
|
169
|
+
def indent
|
170
|
+
" " * @indent
|
171
|
+
end
|
172
|
+
|
173
|
+
def open_tag(name)
|
174
|
+
@output.puts("#{indent}<#{name}>")
|
175
|
+
@indent += 2
|
176
|
+
if block_given?
|
177
|
+
yield
|
178
|
+
close_tag(name)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_content(name, content)
|
183
|
+
return if content.nil?
|
184
|
+
case content
|
185
|
+
when Time
|
186
|
+
content = content.iso8601
|
187
|
+
end
|
188
|
+
@output.puts("#{indent}<#{name}>#{h(content)}</#{name}>")
|
189
|
+
end
|
190
|
+
|
191
|
+
def close_tag(name)
|
192
|
+
@indent -= 2
|
193
|
+
@output.puts("#{indent}</#{name}>")
|
194
|
+
end
|
195
|
+
|
196
|
+
def output_test(test)
|
197
|
+
open_tag("test") do
|
198
|
+
add_content("name", test.method_name)
|
199
|
+
add_content("start-time", test.start_time)
|
200
|
+
add_content("elapsed", test.elapsed_time)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def output_test_suite(test_suite)
|
205
|
+
test_case = test_suite.test_case
|
206
|
+
if test_case.nil?
|
207
|
+
open_tag("test-suite") do
|
208
|
+
add_content("name", test_suite.name)
|
209
|
+
add_content("start-time", test_suite.start_time)
|
210
|
+
add_content("elapsed", test_suite.elapsed_time)
|
211
|
+
end
|
212
|
+
else
|
213
|
+
open_tag("test-case") do
|
214
|
+
add_content("name", test_suite.name)
|
215
|
+
add_content("start-time", test_suite.start_time)
|
216
|
+
add_content("elapsed", test_suite.elapsed_time)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|