RSpec is Growing on Me
I'm a big believer in Test-Driven Development. Chris Brooks turned me on to Ruby on Rails at least six years ago, and I embraced it immediately, largely because TDD was well-supported. More recently, Chris pointed me to RSpec and Cucumber for test-driven development.
At first glance, I didn't really see the point or the incremental benefit over Test::Unit as built into Ruby on Rails. Using RSpec involves the chore of managing additional gems, and it just doesn't feel right to ignore the perfectly useful
test/ directory and associated Rake tasks generated by every Rails project. RSpec syntax is more like English, but this seemed to promise capabilities over Test::Unit that I couldn't see being delivered. I found the religious debate entertaining, and came down on DHH's side. However, given Ryan Bates's recommendation, on top of Chris's, I kept an open mind.
Having written several RSpec specs for Rails 2.3.5 and Rails 3.0 projects, I must say, it is growing on me. Here's why...
- Syntax: Much of the benefit I derive from RSpec is from its syntax. I am surprised that syntactic sugar could be so sweet. The
describe-it-shouldsyntax keeps reminding me that my code is meant to solve a customer problem. When I write RSpec specs, I feel I am writing an executable specification of my software. I feel I can easily and smoothly translate customer needs into RSpec specs. Traceability between test cases on the one hand and requirements (including defect resolutions) is important, and RSpec seems to provide the right amount of syntactic sugar to facilitate it. I've come to believe that the most important quality of code is its ability to express intent clearly and concisely. The RSpec syntax seems to support communication of intent beyond the limits of the code under test. The assertions of Test::Unit seem to assume lines of code did what I intended them to do.
test-assertmakes me focus on return values and types. It is a difference of orientation, like the difference between asking "Will this make my customer successful?" and asking "Did this code do what I hoped it did?" I know it is just syntactic sugar, but based on my background, I find the former question more productive and profitable, and the RSpec syntax orients me toward it. It is a bit surprising that the Rails framework generates "unit," "functional," and "integration" directories, while RSpec documentation recommends "model," "controller," "view," and "spec" directories. Given the difference in syntax orientation, one would expect the opposite. However, the RSpec approach definitely feels comfortable.
- Mock objects: RSpec's incremental benefit over Test::Unit is its inclusion of mock objects. Test::Unit can easily use mock objects, but they are not built in (I think). To be honest, I never really understood mock objects until I found them in RSpec and tried using them in my specs. Now, they seem indispensable, well worth the management of additional gems.
The jury is still out on Cucumber. When I gave it a solid try, I found it hard to start. Should I specify high-level, non-technical features and capabilities or low-level, technical expectations? Both are important, so how and where should they live? Perhaps I should start a new development project with Cucumber tests, rather than trying to add them to an existing project.