Recently I’ve been refactoring legacy Test::Unit code to use shoulda. Sometimes you can’t factor out repetitive stuff into a context, but you still want to be DRY. Below is an example case of refactoring into a custom should. Note that you need to use class variables, and that the self.should_* method needs to be defined before it’s actually used, since shoulda is built upon metaprogramming which gets evaluated at the class level.
...
def self.should_request sym
sym = sym.to_s
context "when requesting #{sym}" do
setup do
get :download, {:id => @@podcast.id, :type => sym}, @@session
end
should "ask for a device" do
assert_match /Please select a device to download content/, @response.body
end
should "increment the message count when sent #add_to_device" do
assert_difference 'Message.count( :conditions => "device_id = 1")', @@podcast.episodes.size do
xhr :post, :add_to_device, {:id => 1, :type => 'all', :podcast_id => @@podcast.id}, @@session
end
end
end
end
context "A valid account" do
setup do
@account = accounts(:accounts_002)
@@session = {:account_id => @account.id}
@account.devices << Device.find(1)
@@podcast = podcasts(:joe_cartoon)
@@session.merge!({:podcast_episodes => @@podcast.episodes})
end
should_request :all
should_request :latest
should_request :episode
end
...
We hosted the SF Ruby Meetup last night, which was a smashing success. It was fun to have 50+ Ruby geeks crammed into our office. :)
Here are the slides from my presentation about Shoulda.
I’m pleased to announce a textmate bundle that I assembled for the wonderfully simple shoulda testing framework.
The snippets were contributed by Dan Croak, James Golick, and Sam Livingston-Gray, and mashed up by me.
Grab the latest version here: http://macromates.com/svn/Bundles/trunk/Review/Bundles/Ruby%20Shoulda.tmbundle
Inspired by err’s cryptic yaml_to_spec rake task, I wrote my own version for shoulda, based off of Jeremy Hubert’s textmate bundle It’s a bit less cryptic, and it for extra nerd points it uses recursion to allow for nested contexts. :)
desc "Converts a YAML file into a Shoulda skeleton"
task :yaml_to_shoulda do
require 'yaml'
def yaml_to_context hash, indent=0
indent1 = ' '*indent
indent2 = ' '*(indent+1)
hash.each_pair do |context,shoulds|
puts indent1+"context \"#{context}\" do"
puts
shoulds.each do |should|
yaml_to_context( should, indent+1 ) and next if should.is_a?( Hash )
puts indent2+"should_eventually \"#{should.gsub(/^should +/,'')}\" do"
puts indent2+"end"
puts
end
puts indent1+"end"
end
yaml_to_context( YAML.load_file( ENV['FILE'] || !puts("Pass in FILE argument.") && exit ) )
end
Here is an example YAML file and it’s output:
This blog post: - should mention shoulda - should be concise - should be written by me - when saved as a draft: - should have multiple revisions - should not be published publiclycontext "This blog post" do should_eventually "mention shoulda" do end should_eventually "be concise" do end should_eventually "be written by me" do end context "when saved as a draft" do should_eventually "have multiple revisions" do end should_eventually "not be published publicly" do end end end
I will be adding this to my shoulda textmate bundle.
This morning I just discovered Shoulda, a really sweet testing framework that gives context and behavior without the whizz-bang syntax of RSpec and test-spec. Check it out!
My only complaints so far:
- the example code on their homepage is missing “do” keywords after some of the “should” statements. oops!
- I can no longer run an individual test in textmate with APPLE-shift-R, as there is no literal method to run, just a block. Hopefully this will be fixed with a forthcoming shoulda textmate bundle.
