This post originated from an RSS feed registered with Ruby Buzz
by Patrick Lenz.
Original Post: test/spec on Rails and assert_difference
Feed Title: poocs.net
Feed URL: http://feeds.feedburner.com/poocsnet
Feed Description: Personal weblog about free and open source software, personal development projects and random geek buzz.
I have a certain feeling that the style of doing Behavior Driven Development (BDD) sees a little more adoption than, say, a year ago. With RSpec being the more rigorous kid on the block, test/spec by Christian Neukirchen seems to be a little less intruiging. (Yes, RSpec does have its place, too.)
What is test/spec after all?
To quote its website:
test/spec layers an RSpec-inspired interface on top of Test::Unit, so you can mix TDD and BDD (Behavior-Driven Development).
This especially convenient if you���re porting tests of an existing application over from TDD to BDD-style. test/spec blessed tests can be run alongside of Test::Unit based tests and they can even live in the same files if you dare. For a more thorough explanation of the reasoning behind BDD, see its Wikipedia entry.
This new version (which, technically, isn���t a version after all ��� we���re talking Subversion revisions here) provides all sorts of handy wrappers for more Rails-specific assertions, that previously had to be used in all their nakedness and purity before. Here���s a rundown of the new prettyness:
If you���ve ever used assert_difference before (the original of which appeared as a code snippet on project.ion.ist), you���re probably unable to live without it. Not having to store before states manually to compare them to an after state in your tests is such a simple, yet effective way to DRY up your tests.
def test_new_publication
assert_difference(Publication, :count) do
post :create, :publication => {...}
# ...
end
end
But now that you���ve been drinking the test/spec kool-aid, what���s that assert_something call doing in your test? Well, what about this:
context 'Blog' do
specify 'should create blog' do
lambda {
Blog.create :title => '...'
}.should.change(Blog, :count)
end
end
Admittedly, the lambda { } part isn���t the sexiest on the planet. But it fits nicely into the rest of the ���should��� specifications. Oh, and there���s a ���not��� part, too!
Here���s the code that makes this work (assuming you���ve installed the test_spec gem1 and the test_spec_on_rails plugin2). Just put it at the bottom of test/test_helper.rb.
# Credits: http://project.ioni.st/post/218#post-218
module Test::Unit::AssertDifference
def assert_difference(object, method = nil, difference = 1)
initial_value = object.send(method)
yield
assert_equal initial_value + difference, object.send(method), "#{object}##{method}"
end
def assert_no_difference(object, method, &block)
assert_difference object, method, 0, &block
end
end
# Extension for test/spec/rails, wraps assert_difference
module Test::Spec::Rails
module ShouldDiffer
def differ(*args)
assert_difference(*args, &@object)
end
alias :different :differ
alias :change :differ
end
module ShouldNotDiffer
def differ(*args)
assert_no_difference(*args, &@object)
end
alias :different :differ
alias :change :differ
end
end
Test::Spec::Should.send(:include, Test::Unit::AssertDifference)
Test::Spec::Should.send(:include, Test::Spec::Rails::ShouldDiffer)
Test::Spec::ShouldNot.send(:include, Test::Unit::AssertDifference)
Test::Spec::ShouldNot.send(:include, Test::Spec::Rails::ShouldNotDiffer)