It's all fine and dandy to know what unit testing is, but how do you actually do it? Isn't it really hard and complex? Good question! Let's see...
We need to write some code to wrap strings. Before we start writing the code, lets write a test to see if it works. Here's the test:
def testWrap
end
That's it! There's nothing more to it! All a test is is a method. Of course, ours doesn't actually check anything, but all you need for a test is a method in which to check something. Now, to keep things clean, we'll probably want to wrap the method in a class, like this:
class TC_Wrapper
def testWrap
end
end
Still pretty simple, eh? OK, lets actually do something in our test. We want to make sure that our wrapper wraps our string to a max of 10 characters per line:
class TC_Wrapper
def testWrap
wrapper = Wrapper.new
actualString = wrapper.wrap("This is a long string")
assert_equal("This is a\nlong\nstring")
end
end
Note something very important: the test method is only three lines, and it already checks something very worthwhile! Also note that we haven't written a line of production code yet. So it would be nice if it actually ran, right? That only takes a few more lines of code:
require 'Lapidary/TestCase'
class TC_Wrapper < Lapidary::TestCase
def testWrap
wrapper = Wrapper.new
actualString = wrapper.wrap("This is a long string")
assert_equal("This is a\nlong\nstring")
end
end
if __FILE__ == $0
require 'Lapidary/UI/Console/TestRunner'
Lapidary::UI::Console::TestRunner.run(TC_Wrapper)
end
OK, now we have a test that will run. Lets run it:
C:\rubyconf>ruby TC_Wrapper.rb Loaded suite Started... Error occurred in testWrap(TC_Wrapper): NameError: uninitialized constant Wrapper at TC_Wrapper TC_Wrapper.rb:5:in `testWrap' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestCase.rb:58:in `send' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestCase.rb:58:in `run' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestCase.rb:57:in `catch' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestCase.rb:57:in `run' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestSuite.rb:36:in `run' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestSuite.rb:32:in `each' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/TestSuite.rb:32:in `run' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/UI/TestRunnerMediator.rb:63:in `runSuite' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/UI/Console/TestRunner.rb:65:in `startMediator' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/UI/Console/TestRunner.rb:49:in `start' C:/ruby/lib/ruby/site_ruby/1.7/Lapidary/UI/Console/TestRunner.rb:36:in `run' TC_Wrapper.rb:13 .. Finished in 0.0 seconds. 1 runs, 0 assertions, 0 failures, 1 errors
So the testing framework has caught an error due to our not having a Wrapper class yet. Lets define one, and see if it works:
class Wrapper
def wrap(string)
end
end
So now there's a Wrapper class, and we just need to require it in our test:
require 'Lapidary/TestCase'
require 'Wrapper'
class TC_Wrapper < Lapidary::TestCase
def testWrap
wrapper = Wrapper.new
actualString = wrapper.wrap("This is a long string")
assert_equal("This is a\nlong\nstring")
end
end
if __FILE__ == $0
require 'Lapidary/UI/Console/TestRunner'
Lapidary::UI::Console::TestRunner.run(TC_Wrapper)
end
Here's the output now:
C:\rubyconf>ruby TC_Wrapper.rb Loaded suite Started... Failure occurred in testWrap(TC_Wrapper) [TC_Wrapper.rb:8]: The string should have been wrapped. Exp ected <This is a long string> but was <nil> .. Finished in 0.0 seconds. 1 runs, 0 assertions, 1 failures, 0 errors
This output is, of course, correct, because our wrapper doesn't actually do anything yet. Lets add some wrapping code, and see what happens:
class Wrapper
def wrap(string)
words = string.split(/ /)
line = nil
lines = []
words.each { | word |
if (line.nil?)
line = word
elsif (line.length + word.length + 1 < 10)
line = [line, word].compact.join(" ")
else
lines << line
line = word
end
}
lines << line
lines.join("\n")
end
end
Hmmm.... I wonder if that works.
C:\rubyconf>ruby TC_Wrapper.rb Loaded suite Started... .. Finished in 0.0 seconds. 1 runs, 1 assertions, 0 failures, 0 errors
Cool! We've now written a test, and made it pass. In the actual live demonstration for this presentation, it took many more tries to get the code doing the right thing. However, each step of the way, it was incredibly simple to see if the code was working yet, because the tests always told us.
So now you know how to write a test, and it's time for my second assertion (working backwards, of course)...
Copyright (c) 2001 by Nathaniel Talbott. All Rights Reserved.