Justin Marney, Web Developer, May 26, 2009
Last month David wrote up a good explanation of how to create shoulda macros with blocks. Recently, I needed to reuse context behavior across a few different tests as well. Out of curiosity, I went in search of a more idiomatic solution and was able to find this ticket and its associated conversation. From the discussion surrounding that ticket, I learned that you can use the merge_block method to create nestable context macros.
class Test::Unit::TestCase
def self.context_with_an_object(&block)
context "With an object" do
setup do
@object = {:rock => 'on'}
end
should "do something fantastic" do
assert @object[:rock], 'on'
end
merge_block(&block) if block_given?
end
end
end
You can use the context macro in one of your tests and it will accept a block as well as respect context nesting.
class ModelTest < Test::Unit::TestCase
context "A great and wonderous test" do
setup do
@thing = {:creature => 'lagoon', :rock => 'on'}
end
context_with_an_object do
should "do something specific" do
assert_equal @thing[:rock], @object[:rock]
end
context "And a friend" do
setup do
@friend = {:rock => 'on'}
end
should "respect some nested context insanity" do
assert_equal @friend[:rock], @thing[:rock]
end
end
end
end
end
You can also create your context macros such that they accept arguments.
class Test::Unit::TestCase
def self.context_with_a_modified_object(modifier, &block)
context "with a modified object" do
setup do
@object = {:mod => modifier}
end
merge_block(&block) if block_given?
end
end
end
Modifying the context behavior via an argument allows you to test a handful of edge cases without having to duplicate context code.
class ModelTest < Test::Unit::TestCase
context_with_a_modified_object("dance!") do
should "be modified" do
assert_equal @object[:mod], "dance!"
end
end
end
I recommend using this technique sparingly and only to remove unnecessary duplication among your tests. It is possible to hide too much context behavior behind these macros and end up with tests that are difficult to understand and maintain. For contexts that aren't reused outside of a single file consider defining them at the top of the test file.
Recent Comments
For translating strings you can use Rails I18n backend instead of using inflectors.
The `typus_human_name` is a patch to fix a problem in `human_name` [1].
[1] https://rails.lighthouseapp.com/projects/8994/tickets/2120-humanize-and-human_name-dont-separate-words