1 | require 'test/unit/testcase'
|
---|
2 | require 'test/unit/autorunner'
|
---|
3 |
|
---|
4 | module Test # :nodoc:
|
---|
5 | #
|
---|
6 | # = Test::Unit - Ruby Unit Testing Framework
|
---|
7 | #
|
---|
8 | # == Introduction
|
---|
9 | #
|
---|
10 | # Unit testing is making waves all over the place, largely due to the
|
---|
11 | # fact that it is a core practice of XP. While XP is great, unit testing
|
---|
12 | # has been around for a long time and has always been a good idea. One
|
---|
13 | # of the keys to good unit testing, though, is not just writing tests,
|
---|
14 | # but having tests. What's the difference? Well, if you just _write_ a
|
---|
15 | # test and throw it away, you have no guarantee that something won't
|
---|
16 | # change later which breaks your code. If, on the other hand, you _have_
|
---|
17 | # tests (obviously you have to write them first), and run them as often
|
---|
18 | # as possible, you slowly build up a wall of things that cannot break
|
---|
19 | # without you immediately knowing about it. This is when unit testing
|
---|
20 | # hits its peak usefulness.
|
---|
21 | #
|
---|
22 | # Enter Test::Unit, a framework for unit testing in Ruby, helping you to
|
---|
23 | # design, debug and evaluate your code by making it easy to write and
|
---|
24 | # have tests for it.
|
---|
25 | #
|
---|
26 | #
|
---|
27 | # == Notes
|
---|
28 | #
|
---|
29 | # Test::Unit has grown out of and superceded Lapidary.
|
---|
30 | #
|
---|
31 | #
|
---|
32 | # == Feedback
|
---|
33 | #
|
---|
34 | # I like (and do my best to practice) XP, so I value early releases,
|
---|
35 | # user feedback, and clean, simple, expressive code. There is always
|
---|
36 | # room for improvement in everything I do, and Test::Unit is no
|
---|
37 | # exception. Please, let me know what you think of Test::Unit as it
|
---|
38 | # stands, and what you'd like to see expanded/changed/improved/etc. If
|
---|
39 | # you find a bug, let me know ASAP; one good way to let me know what the
|
---|
40 | # bug is is to submit a new test that catches it :-) Also, I'd love to
|
---|
41 | # hear about any successes you have with Test::Unit, and any
|
---|
42 | # documentation you might add will be greatly appreciated. My contact
|
---|
43 | # info is below.
|
---|
44 | #
|
---|
45 | #
|
---|
46 | # == Contact Information
|
---|
47 | #
|
---|
48 | # A lot of discussion happens about Ruby in general on the ruby-talk
|
---|
49 | # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask
|
---|
50 | # any questions you might have there. I monitor the list, as do many
|
---|
51 | # other helpful Rubyists, and you're sure to get a quick answer. Of
|
---|
52 | # course, you're also welcome to email me (Nathaniel Talbott) directly
|
---|
53 | # at mailto:[email protected], and I'll do my best to help you out.
|
---|
54 | #
|
---|
55 | #
|
---|
56 | # == Credits
|
---|
57 | #
|
---|
58 | # I'd like to thank...
|
---|
59 | #
|
---|
60 | # Matz, for a great language!
|
---|
61 | #
|
---|
62 | # Masaki Suketa, for his work on RubyUnit, which filled a vital need in
|
---|
63 | # the Ruby world for a very long time. I'm also grateful for his help in
|
---|
64 | # polishing Test::Unit and getting the RubyUnit compatibility layer
|
---|
65 | # right. His graciousness in allowing Test::Unit to supercede RubyUnit
|
---|
66 | # continues to be a challenge to me to be more willing to defer my own
|
---|
67 | # rights.
|
---|
68 | #
|
---|
69 | # Ken McKinlay, for his interest and work on unit testing, and for his
|
---|
70 | # willingness to dialog about it. He was also a great help in pointing
|
---|
71 | # out some of the holes in the RubyUnit compatibility layer.
|
---|
72 | #
|
---|
73 | # Dave Thomas, for the original idea that led to the extremely simple
|
---|
74 | # "require 'test/unit'", plus his code to improve it even more by
|
---|
75 | # allowing the selection of tests from the command-line. Also, without
|
---|
76 | # RDoc, the documentation for Test::Unit would stink a lot more than it
|
---|
77 | # does now.
|
---|
78 | #
|
---|
79 | # Everyone who's helped out with bug reports, feature ideas,
|
---|
80 | # encouragement to continue, etc. It's a real privilege to be a part of
|
---|
81 | # the Ruby community.
|
---|
82 | #
|
---|
83 | # The guys at RoleModel Software, for putting up with me repeating, "But
|
---|
84 | # this would be so much easier in Ruby!" whenever we're coding in Java.
|
---|
85 | #
|
---|
86 | # My Creator, for giving me life, and giving it more abundantly.
|
---|
87 | #
|
---|
88 | #
|
---|
89 | # == License
|
---|
90 | #
|
---|
91 | # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free
|
---|
92 | # software, and is distributed under the Ruby license. See the COPYING
|
---|
93 | # file in the standard Ruby distribution for details.
|
---|
94 | #
|
---|
95 | #
|
---|
96 | # == Warranty
|
---|
97 | #
|
---|
98 | # This software is provided "as is" and without any express or
|
---|
99 | # implied warranties, including, without limitation, the implied
|
---|
100 | # warranties of merchantibility and fitness for a particular
|
---|
101 | # purpose.
|
---|
102 | #
|
---|
103 | #
|
---|
104 | # == Author
|
---|
105 | #
|
---|
106 | # Nathaniel Talbott.
|
---|
107 | # Copyright (c) 2000-2003, Nathaniel Talbott
|
---|
108 | #
|
---|
109 | # ----
|
---|
110 | #
|
---|
111 | # = Usage
|
---|
112 | #
|
---|
113 | # The general idea behind unit testing is that you write a _test_
|
---|
114 | # _method_ that makes certain _assertions_ about your code, working
|
---|
115 | # against a _test_ _fixture_. A bunch of these _test_ _methods_ are
|
---|
116 | # bundled up into a _test_ _suite_ and can be run any time the
|
---|
117 | # developer wants. The results of a run are gathered in a _test_
|
---|
118 | # _result_ and displayed to the user through some UI. So, lets break
|
---|
119 | # this down and see how Test::Unit provides each of these necessary
|
---|
120 | # pieces.
|
---|
121 | #
|
---|
122 | #
|
---|
123 | # == Assertions
|
---|
124 | #
|
---|
125 | # These are the heart of the framework. Think of an assertion as a
|
---|
126 | # statement of expected outcome, i.e. "I assert that x should be equal
|
---|
127 | # to y". If, when the assertion is executed, it turns out to be
|
---|
128 | # correct, nothing happens, and life is good. If, on the other hand,
|
---|
129 | # your assertion turns out to be false, an error is propagated with
|
---|
130 | # pertinent information so that you can go back and make your
|
---|
131 | # assertion succeed, and, once again, life is good. For an explanation
|
---|
132 | # of the current assertions, see Test::Unit::Assertions.
|
---|
133 | #
|
---|
134 | #
|
---|
135 | # == Test Method & Test Fixture
|
---|
136 | #
|
---|
137 | # Obviously, these assertions have to be called within a context that
|
---|
138 | # knows about them and can do something meaningful with their
|
---|
139 | # pass/fail value. Also, it's handy to collect a bunch of related
|
---|
140 | # tests, each test represented by a method, into a common test class
|
---|
141 | # that knows how to run them. The tests will be in a separate class
|
---|
142 | # from the code they're testing for a couple of reasons. First of all,
|
---|
143 | # it allows your code to stay uncluttered with test code, making it
|
---|
144 | # easier to maintain. Second, it allows the tests to be stripped out
|
---|
145 | # for deployment, since they're really there for you, the developer,
|
---|
146 | # and your users don't need them. Third, and most importantly, it
|
---|
147 | # allows you to set up a common test fixture for your tests to run
|
---|
148 | # against.
|
---|
149 | #
|
---|
150 | # What's a test fixture? Well, tests do not live in a vacuum; rather,
|
---|
151 | # they're run against the code they are testing. Often, a collection
|
---|
152 | # of tests will run against a common set of data, also called a
|
---|
153 | # fixture. If they're all bundled into the same test class, they can
|
---|
154 | # all share the setting up and tearing down of that data, eliminating
|
---|
155 | # unnecessary duplication and making it much easier to add related
|
---|
156 | # tests.
|
---|
157 | #
|
---|
158 | # Test::Unit::TestCase wraps up a collection of test methods together
|
---|
159 | # and allows you to easily set up and tear down the same test fixture
|
---|
160 | # for each test. This is done by overriding #setup and/or #teardown,
|
---|
161 | # which will be called before and after each test method that is
|
---|
162 | # run. The TestCase also knows how to collect the results of your
|
---|
163 | # assertions into a Test::Unit::TestResult, which can then be reported
|
---|
164 | # back to you... but I'm getting ahead of myself. To write a test,
|
---|
165 | # follow these steps:
|
---|
166 | #
|
---|
167 | # * Make sure Test::Unit is in your library path.
|
---|
168 | # * require 'test/unit' in your test script.
|
---|
169 | # * Create a class that subclasses Test::Unit::TestCase.
|
---|
170 | # * Add a method that begins with "test" to your class.
|
---|
171 | # * Make assertions in your test method.
|
---|
172 | # * Optionally define #setup and/or #teardown to set up and/or tear
|
---|
173 | # down your common test fixture.
|
---|
174 | # * You can now run your test as you would any other Ruby
|
---|
175 | # script... try it and see!
|
---|
176 | #
|
---|
177 | # A really simple test might look like this (#setup and #teardown are
|
---|
178 | # commented out to indicate that they are completely optional):
|
---|
179 | #
|
---|
180 | # require 'test/unit'
|
---|
181 | #
|
---|
182 | # class TC_MyTest < Test::Unit::TestCase
|
---|
183 | # # def setup
|
---|
184 | # # end
|
---|
185 | #
|
---|
186 | # # def teardown
|
---|
187 | # # end
|
---|
188 | #
|
---|
189 | # def test_fail
|
---|
190 | # assert(false, 'Assertion was false.')
|
---|
191 | # end
|
---|
192 | # end
|
---|
193 | #
|
---|
194 | #
|
---|
195 | # == Test Runners
|
---|
196 | #
|
---|
197 | # So, now you have this great test class, but you still need a way to
|
---|
198 | # run it and view any failures that occur during the run. This is
|
---|
199 | # where Test::Unit::UI::Console::TestRunner (and others, such as
|
---|
200 | # Test::Unit::UI::GTK::TestRunner) comes into play. The console test
|
---|
201 | # runner is automatically invoked for you if you require 'test/unit'
|
---|
202 | # and simply run the file. To use another runner, or to manually
|
---|
203 | # invoke a runner, simply call its run class method and pass in an
|
---|
204 | # object that responds to the suite message with a
|
---|
205 | # Test::Unit::TestSuite. This can be as simple as passing in your
|
---|
206 | # TestCase class (which has a class suite method). It might look
|
---|
207 | # something like this:
|
---|
208 | #
|
---|
209 | # require 'test/unit/ui/console/testrunner'
|
---|
210 | # Test::Unit::UI::Console::TestRunner.run(TC_MyTest)
|
---|
211 | #
|
---|
212 | #
|
---|
213 | # == Test Suite
|
---|
214 | #
|
---|
215 | # As more and more unit tests accumulate for a given project, it
|
---|
216 | # becomes a real drag running them one at a time, and it also
|
---|
217 | # introduces the potential to overlook a failing test because you
|
---|
218 | # forget to run it. Suddenly it becomes very handy that the
|
---|
219 | # TestRunners can take any object that returns a Test::Unit::TestSuite
|
---|
220 | # in response to a suite method. The TestSuite can, in turn, contain
|
---|
221 | # other TestSuites or individual tests (typically created by a
|
---|
222 | # TestCase). In other words, you can easily wrap up a group of
|
---|
223 | # TestCases and TestSuites like this:
|
---|
224 | #
|
---|
225 | # require 'test/unit/testsuite'
|
---|
226 | # require 'tc_myfirsttests'
|
---|
227 | # require 'tc_moretestsbyme'
|
---|
228 | # require 'ts_anothersetoftests'
|
---|
229 | #
|
---|
230 | # class TS_MyTests
|
---|
231 | # def self.suite
|
---|
232 | # suite = Test::Unit::TestSuite.new
|
---|
233 | # suite << TC_MyFirstTests.suite
|
---|
234 | # suite << TC_MoreTestsByMe.suite
|
---|
235 | # suite << TS_AnotherSetOfTests.suite
|
---|
236 | # return suite
|
---|
237 | # end
|
---|
238 | # end
|
---|
239 | # Test::Unit::UI::Console::TestRunner.run(TS_MyTests)
|
---|
240 | #
|
---|
241 | # Now, this is a bit cumbersome, so Test::Unit does a little bit more
|
---|
242 | # for you, by wrapping these up automatically when you require
|
---|
243 | # 'test/unit'. What does this mean? It means you could write the above
|
---|
244 | # test case like this instead:
|
---|
245 | #
|
---|
246 | # require 'test/unit'
|
---|
247 | # require 'tc_myfirsttests'
|
---|
248 | # require 'tc_moretestsbyme'
|
---|
249 | # require 'ts_anothersetoftests'
|
---|
250 | #
|
---|
251 | # Test::Unit is smart enough to find all the test cases existing in
|
---|
252 | # the ObjectSpace and wrap them up into a suite for you. It then runs
|
---|
253 | # the dynamic suite using the console TestRunner.
|
---|
254 | #
|
---|
255 | #
|
---|
256 | # == Questions?
|
---|
257 | #
|
---|
258 | # I'd really like to get feedback from all levels of Ruby
|
---|
259 | # practitioners about typos, grammatical errors, unclear statements,
|
---|
260 | # missing points, etc., in this document (or any other).
|
---|
261 | #
|
---|
262 |
|
---|
263 | module Unit
|
---|
264 | # If set to false Test::Unit will not automatically run at exit.
|
---|
265 | def self.run=(flag)
|
---|
266 | @run = flag
|
---|
267 | end
|
---|
268 |
|
---|
269 | # Automatically run tests at exit?
|
---|
270 | def self.run?
|
---|
271 | @run ||= false
|
---|
272 | end
|
---|
273 | end
|
---|
274 | end
|
---|
275 |
|
---|
276 | at_exit do
|
---|
277 | unless $! || Test::Unit.run?
|
---|
278 | exit Test::Unit::AutoRunner.run
|
---|
279 | end
|
---|
280 | end
|
---|