Testing is Rails land is a crazy thing. I’m sure glad that it seems hugely popular, but sometimes I feel people start out with the wrong approach. I originally wrote this as a reply to Unit and Functional Tests are as Useful as 100% Code Coverage.
First, lets clear some things up. 100% test coverage shouldn’t be a goal for your project. I believe that you should track test coverage over time, and make sure that coverage is always increasing rather than diminishing. This metric over time will tell you if you have the right amount of coverage.
Second thing. Rails got it wrong with the name of tests. What Rails considers unit tests aren’t really unit tests. What Rails says are functional tests aren’t quite functional tests, because it seems to me that the integration tests fill the role better. I know this is really a semantic thing, but since we are talking about testing, I’m still on subject.
That being said, I believe there is really only one way to do testing. First you gotta to know what are trying to accomplish. If you are using Cucumber, now is the time to write out those steps and throw on the @wip tag. Now you should run that feature and watch it fail. Failure is a very important part of testing. If you write a test, and it passes the first time, why did you write the test?
OK, now it is time time dive into your test/ or spec/ directory. I think the golden rule of test driven development is this, “Code exists to make your tests pass.” Most likely, you’ll want to start with some kind of controller interaction, so writing a controller spec or functional test is what needs to happen here. Think about this way: you are writing your application from outside in, so think about the interaction points and work from there. In most cases, you can’t hit your models without going through a controller, so it isn’t time to write model tests yet. Testing first is generally pretty easy. The problem that many people run into is that is also time consuming.
My testing pretty much goes like this.
Write the simplest test I can think of
Run the test
Write just enough code to change the error message or make the test pass
Refactor… or not
Repeat
What I find is that I’m moving up and down through my stack. Cucumber –> Functional –> Model –> Functional –> Cucumber –> Functional –> Cucumber.
Now back to this blog post. I really enjoy the spirit of it. I’m afraid it glosses over an important fact though. You need both the feature and the lower level test. The easiest way to think about it is like this: Your features are what you plan to build, and your lower level tests describe how you are building it. You need both of these and one really can’t be more important with the other.