Since I believe we also have something to say about all the fuss involved in testing, here is a 15-point summary on how we do it at BeBanjo, my current employer, as it was presented at Conferencia Rails 2008:
- We perform testing on two different levels: Acceptance and Unit.
- For Acceptance Testing we use Cucumber (formerly Story Runner). Cucumber automatically fills the gap between a user story written in plain English and an executable test.
- For Unit Testing we use RSpec. We could also use Shoulda, Context+Matchy or even Test:Unit+Mocka. Any of these would do. We believe it’s a matter of taste, essentially you can do the same with each of them.
- We find Acceptance Testing excellent as a verification tool, but not as good as a design/development tool.
- We therefore need Unit Testing as a development/design tool to enable us to be more productive and to make our code more maintainable.
- We follow an outside-in approach driven by the user story. We try to write the minimal code necessary to make the next step pass. From the view to the model, outside-in, adding the corresponding specs on the way.
- A comprehensive set of acceptance tests is essential to the way we do specs. If we didn’t have it, we would unit-test in a completely different way.
- We understand that “Mocks aren’t stubs” concludes that there’s no winner between classicists and mockists. It’s all about trade-offs, didn’t you know?
- We only spec the interesting behaviour of the object under test, the behaviour that other parts of the system rely on.
- We don’t usually spec views. We think it is unnecessary with acceptance testing.
- We spec controllers following an interaction-based approach using mocks. Controllers have no state, their interesting behaviour is determined by the way they interact with other objects (models and views). That’s why we think interaction-based testing is the most appropriate for controllers.
- We spec models following a state-based approach. And Rails fixtures are evil. Instead we use any implementation of the Factory pattern (fixture-replacement, FactoryGirl, machinist…)
- We don’t use macros in our specs. Macros encourage a style of testing I call structure-based (vs. state-based or interaction-based), which, in my opinion, gives almost no value. Using them feels like writing the same thing twice. Perhaps because that’s exactly what you’re doing.
- BDD works better when accompanied by other agile practices: pair-programming, refactoring, interface-first, short iterations, etc.
- We are opinionated, like our favourite web framework.
I’m working on a series of posts to elaborate on each of these points. Stay tuned!