Moving to RSpec
RSpec's been on my list of tools to adopt for a while now. My current project is unlikely to migrate from Test::Unit, and there's no plan for me to migrate off that project, so I decided to switch Nestegg over to use it. It's not the sort of hard-core dive-in that's going to force me to get fluent, but it's a nice first baby step. (I'm mean really baby: the whole gem is only one module.)
Here's what the migration looked like.
I started by running
newgem -t rspec fakegem
to get a template for my spec directory and Rakefile, then pulled the
spec-related stuff that generated into nestegg.
The spec folder had
- spec_helper.rb, which just does
require 'spec'
, - spec.opts, which just hash
--colour
, and - fakegem_spec.rb, which is a do-nothing spec.
The Rakefile had this up top
begin
rescue LoadError
puts 'To use rspec for testing you must install rspec gem:'
puts '$ sudo gem install rspec'
exit
end
and this down below
desc "Run the specs under spec"
Spec::Rake::SpecTask.new do |t|
t.spec_opts = ['--options', "spec/spec.opts"]
t.spec_files = FileList['spec/**/*_spec.rb']
end
desc "Default task is to run specs"
task :default => :spec
After a sudo gem install rspec
, I was up and running. The
default rake target ran my Test::Unit suite, then the do-nothing spec.
Sweet.
I moved the do-nothing spec to nestegg/nesting_exception_spec.rb and copied
each of my test names over (which was especially effortless since
my Test::Unit suite was using
RSpec-ish
test declarations). I also remembered reading that you could pass a class to
the describe
method, so I landed with this
describe Nestegg::NestingException do
it "includes cause in backtrace" do
violated "Be sure to write your specs"
end
it "includes cause's backtrace after cause in backtrace" do
violated "Be sure to write your specs"
end
it "removes duplicated backtrace elements from nesting exception" do
violated "Be sure to write your specs"
end
it "defaults cause to current raised exception ($!)" do
violated "Be sure to write your specs"
end
end
Then I started at the top and copied the body of the first test into the spec. I'd anticipated some pain related to the helper methods that lived in my test, but those turned out to be completely portable. The only thing I had to modify in each test was the assertion. With special thanks to the very helpful Test::Unit Cheat Sheet, here are the before-and-afters.
-
became
e.backtrace.should include("cause: StandardError: ")
-
became
e.backtrace[-3..-1].should == ["cause: StandardError: ", "line_one", "line_two"]
-
became
e.backtrace[0..1].should == [" :", "cause: StandardError: msg"]
Note that on that one I'd done a Regexp match in the Test::Unit version, because I didn't want to put the test method name in the content of the test. Since RSpec apparently doesn't create methods out of examples, the backtrace line I'm interested in is free of any method name. To enable a simple equality check, I saved the line number on which the exception was raised in a temporary variable. -
became
raised_error.cause.should == expected_cause
See here for the whole shebang. The original test is here. The two files are incredibly similar, no?
Just like that, Nestegg was converted. I was a little sad I hadn't used mocha, since that could have meant switching to RSpec's mocking library. Oh well. That'll give me something to look forward to when I migrate Handoff.
2 comments:
Nice series, and a great intro comparison of RSpec to Unit - makes me want to rush out and buy one! Thanks for the explanation and examples.
FYI: As you point out, RSpec has its own mocking library built-in, but it also supports others, like Mocha, FlexMock and recently (on trunk) RR - pivotal labs' mock library.
Post a Comment