So I’ve been using RSpec for a while, but sometimes its integration with the Rails framework frustrates me. On the last project I started, I decided not to make waves and just use Test::Unit, which is the Rails default. It’s just easier that way.
Still, there are some things I like about RSpec. One of these things is the ‘this should do that’ syntax, which feels more natural to me. So, ever since I’ve been back on the Test::Unit bandwagon, I’ve been writing by tests in a test_should_do_something_amazing style. (I’ve noticed that a lot of Rails developers are using this style as of late, and even the test stubs that the Rails generators spit out are using this style as well).
Another thing I like about RSpec is its ability to produce a specification document based on your tests, which it calls a SPECDOC. Inspired by the recently added rake task notes, (which enumerates all the commented fixmes, todos, etc. in your app), I figured a SPECDOC enumerator wouldn’t be too hard to add. Here’s a stab at a rake task that does the job. This will rip through your tests, look for specification-style tests, and generate a SPECDOC in the docs directory.
desc "Generate specdoc-style documentation from tests"
namespace :doc do
task :specs do
puts 'Started'
timer, count = Time.now, 0
File.open(RAILS_ROOT + '/doc/SPECDOC', 'w') do |file|
Dir.glob('test/**/*_test.rb').each do |test|
test =~ /.*\/([^\/].*)_test.rb$/
file.puts "#{$1.gsub('_', ' ').capitalize} should:" if $1
File.read(test).map {|line| /test_should_(.*)$/.match line }.compact.each do |spec|
file.puts " * #{spec[1].gsub('_', ' ')}"
sleep 0.001; print '.'; $stdout.flush; count += 1
end
file.puts
end
end
puts "\nFinished in #{Time.now - timer} seconds.\n"
puts "#{count} specifications documented"
end
end
Place this snippet in a file called specdoc.rake and throw it in lib/tasks and you’ll be good to go. Run it using rake doc:specs as follows:
$ rake doc:specs Started .............................................................................. .............................................................................. ...................................... Finished in 2.308674 seconds. 194 specifications documented
The dots and chatter are all just eye-candy, but I thought I’d add them in for good measure. I’m thinking of removing it, though, just to cut down on the code. The SPECDOC will be output to the doc directory.
$ cat doc/SPECDOC Memberships controller should: * require login for protected actions * not require login for public actions * create and send invitations Users controller should: * create user * require unique login on create * require password on create * require password confirmation on create * require email on create * require valid email on create * require authentication * accept authentication * get new user * show user * update user ...
Note that this will only document tests that begin with the aforementioned test_should_ prefix. Test cases that don’t use this convention are ignored, though you could tweak the regex to include them.
My regex-fu may be lacking, so if anyone has any suggestions for how I could make this better, don’t hesitate to pipe up.


Thank you, will test …
Nice tip! One question, though: if you don’t feel like using RSpec, why not just use test/spec? It plays nice with Test::Unit, but gives you BDD goodness. You should check it out.
Looks a bit like the agiledox task described by Ben here – http://www.reevoo.com/blogs/bengriffiths/2005/06/24/a-test-by-any-other-name/
Holy carp, this Rspec thingy looks complicated