ZenTest 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +104 -0
- data/LinuxJournalArticle.txt +393 -0
- data/Manifest.txt +27 -0
- data/README.txt +123 -0
- data/Rakefile +98 -0
- data/bin/ZenTest +28 -0
- data/bin/autotest +12 -0
- data/bin/unit_diff +40 -0
- data/example.txt +41 -0
- data/example1.rb +7 -0
- data/example2.rb +15 -0
- data/lib/ZenTest.rb +536 -0
- data/lib/autotest.rb +202 -0
- data/lib/rails_autotest.rb +57 -0
- data/lib/unit_diff.rb +200 -0
- data/test/data/normal/lib/photo.rb +0 -0
- data/test/data/normal/test/test_camelcase.rb +0 -0
- data/test/data/normal/test/test_photo.rb +0 -0
- data/test/data/normal/test/test_route.rb +0 -0
- data/test/data/normal/test/test_user.rb +0 -0
- data/test/data/rails/test/fixtures/routes.yml +0 -0
- data/test/data/rails/test/functional/route_controller_test.rb +0 -0
- data/test/data/rails/test/unit/route_test.rb +0 -0
- data/test/test_autotest.rb +179 -0
- data/test/test_rails_autotest.rb +55 -0
- data/test/test_unit_diff.rb +95 -0
- data/test/test_zentest.rb +670 -0
- metadata +103 -0
data/History.txt
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
*** 3.0.0 / 2006-03-06
|
2
|
+
|
3
|
+
+ 2 major enhancements
|
4
|
+
+ Added autotest and rails_autotest. YAY for continous testing!
|
5
|
+
+ Repackaged and gemified. YAY for gemification!
|
6
|
+
+ 3 minor enhancements
|
7
|
+
+ Added non-mappable tests starting with test_integration_.
|
8
|
+
+ Lots of code and test refactoring and cleanup.
|
9
|
+
+ Massive improvement on unit tests.
|
10
|
+
+ 3 bug fixes
|
11
|
+
+ Cleaned up class method inheritence. Esp relevant for rails testing.
|
12
|
+
+ Finally fixed the unit_diff parse bug!
|
13
|
+
+ Fixed improper counting of errors if a class was missing, should be 1 + missing methods.
|
14
|
+
|
15
|
+
*** 2.4.0 / 2005-03-21
|
16
|
+
|
17
|
+
+ 3 minor enhancements
|
18
|
+
+ Able to audit standard class library (so now we can audit rubicon!).
|
19
|
+
+ Able to map against class methods (self.blah <=> test_class_blah).
|
20
|
+
+ Added -I=rubypath support
|
21
|
+
+ 4 bug fixes
|
22
|
+
+ bug:1151 Fixed stupid problem w/ unit_diff.
|
23
|
+
+ bug:1454 code generation correctly matches class/module for nested classes.
|
24
|
+
+ bug:1455 Updated method mapping to work on all operators listed in my quickref.
|
25
|
+
+ Realized I'm a moron and did NOT release in March like I thought...
|
26
|
+
|
27
|
+
*** 2.3.0 / 2004-11-18
|
28
|
+
|
29
|
+
+ 6 minor enhancements
|
30
|
+
+ Massively expanded the method name mappings.
|
31
|
+
+ Added -r flag to reverse map names, for Rails style testing.
|
32
|
+
+ Added -e to auto eval tests generated.
|
33
|
+
+ Added -b & -c flags in unit_diff (passed to diff)
|
34
|
+
+ Added install and uninstall rules to Makefile.
|
35
|
+
+ Added some more doco to README.txt
|
36
|
+
+ 7 bug fixes
|
37
|
+
+ Cleaned up and refactored tests.
|
38
|
+
+ Changed the way files are generated, to accomodate new flags.
|
39
|
+
+ Added some more tests.
|
40
|
+
+ Added $ZENTEST=true
|
41
|
+
+ Fixed the one-liner diff bug.
|
42
|
+
+ Cleaned up multi-line string diffs by unescaping \n
|
43
|
+
+ Cleaned result for flunks.
|
44
|
+
|
45
|
+
*** 2.2.0 / 2004-10-18
|
46
|
+
|
47
|
+
+ 4 minor enhancements
|
48
|
+
+ Added LinuxJournalArticle.txt! WOOT!
|
49
|
+
+ Added unit_diff.rb - a very cool filter for test output!
|
50
|
+
+ Extended ZenTest to work with standard input
|
51
|
+
+ Added "ZenTest FULL" to force ZenTest to analyze inherited methods, for subclasses of the standard library.
|
52
|
+
+ 3 bug fixes
|
53
|
+
+ Extended makefile to be more dynamic and stop diffing versions. ugh.
|
54
|
+
+ Expanded the method rename map to handle <<, *, +, and ==.
|
55
|
+
+ Added more test cases.
|
56
|
+
|
57
|
+
*** 2.1.2 / 2004-03-08
|
58
|
+
|
59
|
+
+ 3 bug fixes
|
60
|
+
+ Fixed yet another 1.8ism, results will be the same in 1.8 and 1.6.
|
61
|
+
+ Fixed code responsible for method name conversion.
|
62
|
+
+ I am a moron... didn't run tests after updating version.
|
63
|
+
+ Need to convert my diff-based tests to unit tests.
|
64
|
+
|
65
|
+
*** 2.1.1 / 2004-03-06
|
66
|
+
|
67
|
+
+ 3 bug fixes
|
68
|
+
+ Fixed a 1.8ism.
|
69
|
+
+ Removed zentestrunner. Older ruby users will just have to suffer.
|
70
|
+
+ Updated history to ZenWeb format.
|
71
|
+
|
72
|
+
*** 2.1.0 / 2003-01-07
|
73
|
+
|
74
|
+
+ 3 major enhancements
|
75
|
+
+ Output is runnable as-is thanks to zentestrunner.rb.
|
76
|
+
+ Wrapped up all running functionality into ZenTest.fix
|
77
|
+
+ Added simple statistic output... Thanks Dave & Andy!!!
|
78
|
+
+ 1 minor enhancement
|
79
|
+
+ Added zentestrunner.rb until Nathaniel accepts my changes!
|
80
|
+
+ 3 bug fixes
|
81
|
+
+ Removed at_exit override and avoided test/unit altogether.
|
82
|
+
+ Added a clean rule to Makefile
|
83
|
+
+ Extended README.txt to include some of the rules.
|
84
|
+
+ Fixed several tests and added assertions for new stats
|
85
|
+
|
86
|
+
*** 2.0.0 / 2002-10-29
|
87
|
+
|
88
|
+
+ 2 major enhancements
|
89
|
+
+ Rewrite of ZenTest.rb into actual OO design.
|
90
|
+
+ Added unit tests, finally...
|
91
|
+
|
92
|
+
*** 1.0.1 / 2002-09-28
|
93
|
+
|
94
|
+
+ 1 minor enhancements
|
95
|
+
+ Only loads when a class is detected, allows some scripts to be skipped.
|
96
|
+
+ 3 bug fixes
|
97
|
+
+ Cleaned up output. Verbose when $DEBUG is true.
|
98
|
+
+ Added an error count that is output at end.
|
99
|
+
+ Better filtering or conversion on some method names.
|
100
|
+
|
101
|
+
*** 1.0.0 / 2002-09-24
|
102
|
+
|
103
|
+
+ 1 major enhancements
|
104
|
+
+ Birthday!
|
@@ -0,0 +1,393 @@
|
|
1
|
+
How to Use ZenTest with Ruby
|
2
|
+
by Pat Eyler <pate@kohalabs.com>
|
3
|
+
http://linuxjournal.com/article.php?sid=7776
|
4
|
+
(included in this package with permission)
|
5
|
+
|
6
|
+
Refactoring and unit testing are a great pair of tools for every
|
7
|
+
programmer's workbench. Sadly, not every programmer knows how to use
|
8
|
+
them. My first exposure to them came when I started using Ruby,
|
9
|
+
refactoring and unit testing are a big part of the landscape in the
|
10
|
+
Ruby community.
|
11
|
+
|
12
|
+
Some time ago, I translated the refactoring example from the first
|
13
|
+
chapter of Martin Fowler's excellent book, Refactoring, out of Java
|
14
|
+
and into Ruby. I felt this would be a great way to learn more about
|
15
|
+
refactoring and brush up on my Ruby while I was at it. Recently, I
|
16
|
+
decided to update the translation for Ruby 1.8.X. One of the things I
|
17
|
+
needed to change was to convert the old unit tests to work with
|
18
|
+
Test::Unit, the new unit testing framework for Ruby.
|
19
|
+
|
20
|
+
I wasn't really looking forward to building a new test suite though.
|
21
|
+
Fortunately, help was available. Ryan Davis has written a great tool
|
22
|
+
called ZenTest, which creates test suites for existing bodies of
|
23
|
+
code. Since a lot of people are new to refactoring, unit testing, and
|
24
|
+
ZenTest, I thought this would be a great chance to introduce you to
|
25
|
+
this trio of tools.
|
26
|
+
|
27
|
+
Martin's example code is built around a video store application. In
|
28
|
+
his original code, there are three classes; Customer, Movie, and
|
29
|
+
Rental. I'll focus on just the Customer class in this article.
|
30
|
+
Here's the original code:
|
31
|
+
|
32
|
+
class Customer
|
33
|
+
attr_accessor :name
|
34
|
+
|
35
|
+
def initialize(name)
|
36
|
+
@name = name
|
37
|
+
@rentals = Array.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def addRental(aRental)
|
41
|
+
@rentals.push(aRental)
|
42
|
+
end
|
43
|
+
|
44
|
+
def statement
|
45
|
+
totalAmount = 0.0
|
46
|
+
frequentRenterPoints = 0
|
47
|
+
rentals = @rentals.length
|
48
|
+
result = "\nRental Record for #{@name}\n"
|
49
|
+
thisAmount = 0.0
|
50
|
+
@rentals.each do |rental|
|
51
|
+
# determine amounts for each line
|
52
|
+
case rental.aMovie.pricecode
|
53
|
+
when Movie::REGULAR
|
54
|
+
thisAmount += 2
|
55
|
+
if rental.daysRented > 2
|
56
|
+
thisAmount += (rental.daysRented - 2) * 1.5
|
57
|
+
end
|
58
|
+
|
59
|
+
when Movie::NEW_RELEASE
|
60
|
+
thisAmount += rental.daysRented * 3
|
61
|
+
|
62
|
+
when Movie::CHILDRENS
|
63
|
+
thisAmount += 1.5
|
64
|
+
if each.daysRented > 3
|
65
|
+
thisAmount += (rental.daysRented - 3) * 1.5
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
# add frequent renter points
|
71
|
+
frequentRenterPoints += 1
|
72
|
+
# add bonus for a two day new release rental
|
73
|
+
if ( rental.daysRented > 1) &&
|
74
|
+
(Movie::NEW_RELEASE == rental.aMovie.pricecode)
|
75
|
+
frequentRenterPoints += 1
|
76
|
+
end
|
77
|
+
|
78
|
+
# show figures for this rental
|
79
|
+
result +="\t#{rental.aMovie.title}\t#{thisAmount}\n"
|
80
|
+
totalAmount += thisAmount
|
81
|
+
end
|
82
|
+
result += "Amount owed is #{totalAmount}\n"
|
83
|
+
result += "You earned #{frequentRenterPoints} frequent renter points"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
Not the cleanest code in the world, but it is supposed to be that
|
89
|
+
way. This represents the code as you get it from the user. No
|
90
|
+
tests, poorly laid out, but working -- and it's your job to make it
|
91
|
+
better without breaking it. So, where to start? With unit tests of
|
92
|
+
course.
|
93
|
+
|
94
|
+
Time to grab ZenTest. You can run it like this:
|
95
|
+
|
96
|
+
$ zentest videostore.rb > test_videostore.rb
|
97
|
+
|
98
|
+
which produces a file full of tests. Running the test suite doesn't
|
99
|
+
do quite what we were hoping though:
|
100
|
+
|
101
|
+
$ ruby testVideoStore.rb Loaded suite testVideoStore
|
102
|
+
Started
|
103
|
+
EEEEEEEEEEE
|
104
|
+
Finished in 0.008974 seconds.
|
105
|
+
|
106
|
+
1) Error!!!
|
107
|
+
test_addRental(TestCustomer):
|
108
|
+
NotImplementedError: Need to write test_addRental
|
109
|
+
testVideoStore.rb:11:in `test_addRental'
|
110
|
+
testVideoStore.rb:54
|
111
|
+
|
112
|
+
2) Error!!!
|
113
|
+
test_name=(TestCustomer):
|
114
|
+
NotImplementedError: Need to write test_name=
|
115
|
+
testVideoStore.rb:15:in `test_name='
|
116
|
+
testVideoStore.rb:54
|
117
|
+
|
118
|
+
3) Error!!!
|
119
|
+
test_statement=(TestCustomer):
|
120
|
+
NotImplementedError: Need to write test_statement
|
121
|
+
testVideoStore.rb:19:in `test_statement'
|
122
|
+
testVideoStore.rb:54
|
123
|
+
.
|
124
|
+
.
|
125
|
+
.
|
126
|
+
|
127
|
+
11 tests, 0 assertions, 0 failures, 11 errors
|
128
|
+
$
|
129
|
+
|
130
|
+
So what exactly did we get out of this? Here's the portion of our
|
131
|
+
new test suite that matters for the Customer class:
|
132
|
+
|
133
|
+
# Code Generated by ZenTest v. 2.1.2
|
134
|
+
# classname: asrt / meth = ratio%
|
135
|
+
# Customer: 0 / 3 = 0.00%
|
136
|
+
|
137
|
+
require 'test/unit'
|
138
|
+
|
139
|
+
class TestCustomer < Test::Unit::TestCase
|
140
|
+
def test_addRental
|
141
|
+
raise NotImplementedError, 'Need to write test_addRental'
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_name=
|
145
|
+
raise NotImplementedError, 'Need to write test_name='
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_statement
|
149
|
+
raise NotImplementedError, 'Need to write test_statement'
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
ZenTest built three test methods: one for the accessor method, one for
|
154
|
+
the addRental method, and one for the statement method. Why nothing
|
155
|
+
for the initializer? Well, initializers tend to be pretty bulletproof
|
156
|
+
(if they're not, it's pretty easy to add the test method yourself).
|
157
|
+
Besides, we'll be testing it indirectly when we write test_name= (the
|
158
|
+
tests for the accessor method). There's one other thing we'll need to
|
159
|
+
add, the test suite doesn't load the code we're testing. Changing the
|
160
|
+
beginning of the script to require the videostore.rb file will do the
|
161
|
+
trick for us.
|
162
|
+
|
163
|
+
|
164
|
+
# Code Generated by ZenTest v. 2.1.2
|
165
|
+
# classname: asrt / meth = ratio%
|
166
|
+
# Customer: 0 / 3 = 0.00%
|
167
|
+
|
168
|
+
require 'test/unit'
|
169
|
+
require 'videostore'
|
170
|
+
|
171
|
+
That little snippet of comments at the top lets us know that we have three
|
172
|
+
methods under test in the Customer class, zero assertions testing
|
173
|
+
them, and no coverage. Let's fix that. We'll start by writing some
|
174
|
+
tests for test_name= (no, it really doesn't matter what order we go in --
|
175
|
+
this is just a convenient place to start).
|
176
|
+
|
177
|
+
def test_name=
|
178
|
+
aCustomer = Customer.new("Fred Jones")
|
179
|
+
assert_equal("Fred Jones",aCustomer.name)
|
180
|
+
aCustomer.name = "Freddy Jones"
|
181
|
+
assert_equal("Freddy Jones",aCustomer.name
|
182
|
+
end
|
183
|
+
|
184
|
+
Running testVideoStore.rb again gives us:
|
185
|
+
|
186
|
+
$ ruby testVideoStore.rb
|
187
|
+
Loaded suite testVideoStore
|
188
|
+
Started
|
189
|
+
E.EEEEEEEEE
|
190
|
+
Finished in 0.011233 seconds.
|
191
|
+
|
192
|
+
1) Error!!!
|
193
|
+
test_addRental(TestCustomer):
|
194
|
+
NotImplementedError: Need to write test_addRental
|
195
|
+
testVideoStore.rb:13:in `test_addRental'
|
196
|
+
testVideoStore.rb:58
|
197
|
+
|
198
|
+
2) Error!!!
|
199
|
+
test_statement(TestCustomer):
|
200
|
+
NotImplementedError: Need to write test_statement
|
201
|
+
testVideoStore.rb:23:in `test_statement'
|
202
|
+
testVideoStore.rb:58
|
203
|
+
.
|
204
|
+
.
|
205
|
+
.
|
206
|
+
11 tests, 2 assertions, 0 failures, 10 errors
|
207
|
+
$
|
208
|
+
|
209
|
+
So far, so good. The line of 'E's (which shows errors in the test run)
|
210
|
+
has been reduced by one, and the summary line at the bottom tells us
|
211
|
+
roughly the same thing.
|
212
|
+
|
213
|
+
We really don't have a way to test addRental directly, so we'll just
|
214
|
+
write an stub test for now.
|
215
|
+
|
216
|
+
def test_addRental
|
217
|
+
assert(1) # stub test, since there is nothing in the method to test
|
218
|
+
end
|
219
|
+
|
220
|
+
When we run the tests again, we get:
|
221
|
+
|
222
|
+
$ ruby testVideoStore.rb
|
223
|
+
Loaded suite testVideoStore
|
224
|
+
Started
|
225
|
+
..EEEEEEEEE
|
226
|
+
Finished in 0.008682 seconds.
|
227
|
+
|
228
|
+
1) Error!!!
|
229
|
+
test_statement(TestCustomer):
|
230
|
+
NotImplementedError: Need to write test_statement
|
231
|
+
testVideoStore.rb:22:in `test_statement'
|
232
|
+
testVideoStore.rb:57
|
233
|
+
.
|
234
|
+
.
|
235
|
+
.
|
236
|
+
11 tests, 3 assertions, 0 failures, 9 errors
|
237
|
+
$
|
238
|
+
|
239
|
+
Better and better, just one error left in the TestCustomer class.
|
240
|
+
Let's finish up with a test that will clear our test_statement error
|
241
|
+
and verify that addRental works correctly:
|
242
|
+
|
243
|
+
def test_statement
|
244
|
+
aMovie = Movie.new("Legacy",0)
|
245
|
+
|
246
|
+
aRental = Rental.new(aMovie,2)
|
247
|
+
|
248
|
+
aCustomer = Customer.new("Fred Jones")
|
249
|
+
aCustomer.addRental(aRental)
|
250
|
+
aStatement = "\nRental Record for Fred Jones\n\tLegacy\t2.0
|
251
|
+
Amount owed is 2.0\nYou earned 1 frequent renter points"
|
252
|
+
|
253
|
+
assert_equal(aStatement,aCustomer.statement)
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
We run the tests again, and see:
|
258
|
+
|
259
|
+
$ ruby testVideoStore.rb
|
260
|
+
Loaded suite testVideoStore
|
261
|
+
Started
|
262
|
+
...EEEEEEEE
|
263
|
+
Finished in 0.009378 seconds.
|
264
|
+
.
|
265
|
+
.
|
266
|
+
.
|
267
|
+
11 tests, 4 assertions, 0 failures, 8 errors
|
268
|
+
$
|
269
|
+
|
270
|
+
Great! The only errors left are on the Movie and Rental classes,
|
271
|
+
the Customer class is clean.
|
272
|
+
|
273
|
+
We can continue along like this for the remaining classes, but I'll
|
274
|
+
not bore you with those details. Instead, I'd like to look at how
|
275
|
+
ZenTest can help when you've already got some tests in place. Later
|
276
|
+
development allows us to do just that -- the video store owner
|
277
|
+
wants a new web based statement for web using customers.
|
278
|
+
|
279
|
+
After a bit of refactoring and new development, the code looks like
|
280
|
+
this:
|
281
|
+
|
282
|
+
class Customer
|
283
|
+
attr_accessor :name
|
284
|
+
|
285
|
+
def initialize(name)
|
286
|
+
@name = name
|
287
|
+
@rentals = Array.new
|
288
|
+
end
|
289
|
+
|
290
|
+
def addRental(aRental)
|
291
|
+
@rentals.push(aRental)
|
292
|
+
end
|
293
|
+
|
294
|
+
def statement
|
295
|
+
result = "\nRental Record for #{@name}\n"
|
296
|
+
@rentals.each do
|
297
|
+
|each|
|
298
|
+
# show figures for this rental
|
299
|
+
result +="\t#{each.aMovie.title}\t#{each.getCharge}\n"
|
300
|
+
end
|
301
|
+
result += "Amount owed is #{getTotalCharge}\n"
|
302
|
+
result +=
|
303
|
+
"You earned #{getFrequentRenterPoints} frequent renter points"
|
304
|
+
end
|
305
|
+
|
306
|
+
def htmlStatement
|
307
|
+
result = "\n<H1>Rentals for <EM>#{name}</EM></H1><P>\n"
|
308
|
+
@rentals.each do
|
309
|
+
|each|
|
310
|
+
result += "#{each.aMovie.title}: #{each.getCharge}<BR>\n"
|
311
|
+
end
|
312
|
+
result += "You owe <EM>#{getTotalCharge}</EM><P>\n"
|
313
|
+
result +=
|
314
|
+
"On this rental you earned <EM>#{getFrequentRenterPoints}" +
|
315
|
+
"</EM> frequent renter points<P>"
|
316
|
+
end
|
317
|
+
|
318
|
+
def getTotalCharge
|
319
|
+
result = 0.0
|
320
|
+
@rentals.each do
|
321
|
+
|each|
|
322
|
+
result += each.getCharge()
|
323
|
+
end
|
324
|
+
result
|
325
|
+
end
|
326
|
+
|
327
|
+
def getFrequentRenterPoints
|
328
|
+
result = 0
|
329
|
+
@rentals.each do
|
330
|
+
|each|
|
331
|
+
result += each.getFrequentRenterPoints
|
332
|
+
end
|
333
|
+
result
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
There's a lot of new stuff in here. If we run ZenTest again, it'll
|
338
|
+
pick up the methods we don't have any coverage on (we should have
|
339
|
+
written them as we wrote the new methods, but this is a bit more
|
340
|
+
illustrative). This time, we'll invoke ZenTest a little bit
|
341
|
+
differently:
|
342
|
+
|
343
|
+
$ zentest videostore.rb testVideoStore.rb > Missing_tests
|
344
|
+
|
345
|
+
and our (trimmed) output looks like this:
|
346
|
+
|
347
|
+
# Code Generated by ZenTest v. 2.1.2
|
348
|
+
# classname: asrt / meth = ratio%
|
349
|
+
# Customer: 4 / 6 = 66.67%
|
350
|
+
|
351
|
+
|
352
|
+
require 'test/unit'
|
353
|
+
|
354
|
+
class TestCustomer < Test::Unit::TestCase
|
355
|
+
def test_getFrequentRenterPoints
|
356
|
+
raise NotImplementedError,
|
357
|
+
'Need to write test_getFrequentRenterPoints'
|
358
|
+
end
|
359
|
+
|
360
|
+
def test_getTotalCharge
|
361
|
+
raise NotImplementedError, 'Need to write test_getTotalCharge'
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_htmlStatement
|
365
|
+
raise NotImplementedError, 'Need to write test_htmlStatement'
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
Hmmm, three more test methods to fill in to get our complete
|
370
|
+
coverage. As we write these, we can just migrate them into our
|
371
|
+
existing testVideoStore.rb test suite. Then we can keep moving ahead
|
372
|
+
with refactoring and adding new features. In the future, let's just
|
373
|
+
be sure we add tests as we go along. ZenTest can help you here too.
|
374
|
+
You can write stubs for new development, then run ZenTest to create
|
375
|
+
your new test stubs as well. After some refactorings (like 'extract
|
376
|
+
method'), ZenTest can be used the same way.
|
377
|
+
|
378
|
+
Refactoring and unit testing are powerful tools for programmers, and
|
379
|
+
ZenTest provides an easy way to start using them in a Ruby
|
380
|
+
environment. Hopefully, this introduction has whetted your appetite.
|
381
|
+
|
382
|
+
If you're interested in learning more about refactoring, please grab a
|
383
|
+
copy of 'Refactoring: Improving the Design of Existing Code' and take
|
384
|
+
a look at www.refactoring.com. For more information about unit
|
385
|
+
testing, please see: c2.com/cgi/wiki?UnitTest,
|
386
|
+
www.junit.org/index.htm, and
|
387
|
+
www.extremeprogramming.org/rules/unittests.html.
|
388
|
+
|
389
|
+
The latest information about Test::Unit and ZenTest are available at
|
390
|
+
their home pages: testunit.talbott.ws (for Test::Unit) and
|
391
|
+
www.zenspider.com/ZSS/Products/ZenTest.
|
392
|
+
|
393
|
+
|