1 | #--
|
---|
2 | #
|
---|
3 | # Author:: Nathaniel Talbott.
|
---|
4 | # Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
|
---|
5 | # License:: Ruby license.
|
---|
6 |
|
---|
7 | require 'test/unit/assertions'
|
---|
8 | require 'test/unit/failure'
|
---|
9 | require 'test/unit/error'
|
---|
10 | require 'test/unit/testsuite'
|
---|
11 | require 'test/unit/assertionfailederror'
|
---|
12 | require 'test/unit/util/backtracefilter'
|
---|
13 |
|
---|
14 | module Test
|
---|
15 | module Unit
|
---|
16 |
|
---|
17 | # Ties everything together. If you subclass and add your own
|
---|
18 | # test methods, it takes care of making them into tests and
|
---|
19 | # wrapping those tests into a suite. It also does the
|
---|
20 | # nitty-gritty of actually running an individual test and
|
---|
21 | # collecting its results into a Test::Unit::TestResult object.
|
---|
22 | class TestCase
|
---|
23 | include Assertions
|
---|
24 | include Util::BacktraceFilter
|
---|
25 |
|
---|
26 | attr_reader :method_name
|
---|
27 |
|
---|
28 | STARTED = name + "::STARTED"
|
---|
29 | FINISHED = name + "::FINISHED"
|
---|
30 |
|
---|
31 | ##
|
---|
32 | # These exceptions are not caught by #run.
|
---|
33 |
|
---|
34 | PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt,
|
---|
35 | SystemExit]
|
---|
36 |
|
---|
37 | # Creates a new instance of the fixture for running the
|
---|
38 | # test represented by test_method_name.
|
---|
39 | def initialize(test_method_name)
|
---|
40 | unless(respond_to?(test_method_name) and
|
---|
41 | (method(test_method_name).arity == 0 ||
|
---|
42 | method(test_method_name).arity == -1))
|
---|
43 | throw :invalid_test
|
---|
44 | end
|
---|
45 | @method_name = test_method_name
|
---|
46 | @test_passed = true
|
---|
47 | end
|
---|
48 |
|
---|
49 | # Rolls up all of the test* methods in the fixture into
|
---|
50 | # one suite, creating a new instance of the fixture for
|
---|
51 | # each method.
|
---|
52 | def self.suite
|
---|
53 | method_names = public_instance_methods(true)
|
---|
54 | tests = method_names.delete_if {|method_name| method_name !~ /^test./}
|
---|
55 | suite = TestSuite.new(name)
|
---|
56 | tests.sort.each do
|
---|
57 | |test|
|
---|
58 | catch(:invalid_test) do
|
---|
59 | suite << new(test)
|
---|
60 | end
|
---|
61 | end
|
---|
62 | if (suite.empty?)
|
---|
63 | catch(:invalid_test) do
|
---|
64 | suite << new("default_test")
|
---|
65 | end
|
---|
66 | end
|
---|
67 | return suite
|
---|
68 | end
|
---|
69 |
|
---|
70 | # Runs the individual test method represented by this
|
---|
71 | # instance of the fixture, collecting statistics, failures
|
---|
72 | # and errors in result.
|
---|
73 | def run(result)
|
---|
74 | yield(STARTED, name)
|
---|
75 | @_result = result
|
---|
76 | begin
|
---|
77 | setup
|
---|
78 | __send__(@method_name)
|
---|
79 | rescue AssertionFailedError => e
|
---|
80 | add_failure(e.message, e.backtrace)
|
---|
81 | rescue Exception
|
---|
82 | raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
|
---|
83 | add_error($!)
|
---|
84 | ensure
|
---|
85 | begin
|
---|
86 | teardown
|
---|
87 | rescue AssertionFailedError => e
|
---|
88 | add_failure(e.message, e.backtrace)
|
---|
89 | rescue Exception
|
---|
90 | raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
|
---|
91 | add_error($!)
|
---|
92 | end
|
---|
93 | end
|
---|
94 | result.add_run
|
---|
95 | yield(FINISHED, name)
|
---|
96 | end
|
---|
97 |
|
---|
98 | # Called before every test method runs. Can be used
|
---|
99 | # to set up fixture information.
|
---|
100 | def setup
|
---|
101 | end
|
---|
102 |
|
---|
103 | # Called after every test method runs. Can be used to tear
|
---|
104 | # down fixture information.
|
---|
105 | def teardown
|
---|
106 | end
|
---|
107 |
|
---|
108 | def default_test
|
---|
109 | flunk("No tests were specified")
|
---|
110 | end
|
---|
111 |
|
---|
112 | # Returns whether this individual test passed or
|
---|
113 | # not. Primarily for use in teardown so that artifacts
|
---|
114 | # can be left behind if the test fails.
|
---|
115 | def passed?
|
---|
116 | return @test_passed
|
---|
117 | end
|
---|
118 | private :passed?
|
---|
119 |
|
---|
120 | def size
|
---|
121 | 1
|
---|
122 | end
|
---|
123 |
|
---|
124 | def add_assertion
|
---|
125 | @_result.add_assertion
|
---|
126 | end
|
---|
127 | private :add_assertion
|
---|
128 |
|
---|
129 | def add_failure(message, all_locations=caller())
|
---|
130 | @test_passed = false
|
---|
131 | @_result.add_failure(Failure.new(name, filter_backtrace(all_locations), message))
|
---|
132 | end
|
---|
133 | private :add_failure
|
---|
134 |
|
---|
135 | def add_error(exception)
|
---|
136 | @test_passed = false
|
---|
137 | @_result.add_error(Error.new(name, exception))
|
---|
138 | end
|
---|
139 | private :add_error
|
---|
140 |
|
---|
141 | # Returns a human-readable name for the specific test that
|
---|
142 | # this instance of TestCase represents.
|
---|
143 | def name
|
---|
144 | "#{@method_name}(#{self.class.name})"
|
---|
145 | end
|
---|
146 |
|
---|
147 | # Overridden to return #name.
|
---|
148 | def to_s
|
---|
149 | name
|
---|
150 | end
|
---|
151 |
|
---|
152 | # It's handy to be able to compare TestCase instances.
|
---|
153 | def ==(other)
|
---|
154 | return false unless(other.kind_of?(self.class))
|
---|
155 | return false unless(@method_name == other.method_name)
|
---|
156 | self.class == other.class
|
---|
157 | end
|
---|
158 | end
|
---|
159 | end
|
---|
160 | end
|
---|