I love testing, I could hardly wait for this meeting of the Chicago Ruby Group. I was not disappointed. Unit tests are cool, but specs are awesome. Whats the difference you say? I think its a more natural way to write your tests, it makes you think of the behaviour of your object and not "oh gosh, I have to write 3 tests for each of my methods."
For example.. take a queue:
class Queue def initialize @thequeue = [] end def empty? @thequeue.size == 0 end def size @thequeue.size end def enqueue( item ) @thequeue.unshift(item) end def dequeue @thequeue.shift end
If you were designing a class, you might write out the following requirements:
A new queue - should be empty A queue with one item - should be length of one
(ok maybe not, its really obvious but you probably should be that obvious in your tests)
A unit test might look like:
def test_new_queue_is_empty @q = Queue.new assert_equal(@q.size, 0) end
Meh.
Check out a spec test:
context "A new queue" do setup do @q = Queue.new end specify "should be empty" do @q.should_be_empty end end
Hey man. That's English. Each test is in a context block, with a setup and specify chunk. Look what happens when you run the test:
E:\server\rubytest\queue>spec -f s queue_spec.rb A new queue - should be empty
Hey! that looks like your spec! You can actually print this out and hand it to a non programmer and say Hey, this is what my code does. Lets see another one:
context "A queue with one item" do setup do @q = Queue.new @q.enqueue("one item") end specify "should be length of one" do @q.size.should_be 1 end end
And the results of both tests:
A new queue - should be empty A queue with one item - should be length of one
You can do more than one specify in a context block. Check this out:
context "A queue with 5 items" do setup do @q = Queue.new 1.upto(5) do |t| @q.enqueue("item #{t}") end end specify "should be length of five" do @q.size.should_be 5 end specify "should be 4 after dequeue" do @q.dequeue @q.size.should_be 4 end specify "should be 6 after adding another one" do @q.enqueue("item 6") @q.size.should_be 6 end end
The setup is run before each of the specify blocks.
The rspec site has a much more in depth tutorial, including a mock object component. As for integration with Rails, there are rake tasks you can use to run the specs on all your modules and a generator to create the barebones spec shells for your Rails apps.
Check it out, a new way of thinking about testing is a good thing!