One of the most common questions asked by developers new to Rails testing is “How do I add tests to an existing Rails project?”
The answer largely depends on your experience level with testing. Here are my answers based on whether you have little testing experience or if you’re already decently comfortable with testing.
If you have little testing experience
If you have little testing experience, I would suggest getting some practice on a fresh Rails app before trying to introduce testing to the existing Rails project you want to add tests to.
Adding tests to an existing project is a distinct skill from writing tests for new projects. Adding tests to an existing project can be difficult even for very experienced testers, for reasons described below.
At the same time, you probably don’t want to wait a year to learn testing before you start enjoying the benefits of testing on your existing Rails app. What I would suggest is to first start a fresh throwaway Rails app for the purpose of learning testing. Then, once you’ve gotten a little experience there, see if you can apply something to your existing Rails app. Then, if things get too hard in the existing app, switch back to the throwaway app so you can strengthen your skills more. Continue switching back and forth until you don’t need to anymore.
If you’re already comfortable with testing
Here’s how I suggest adding tests to an existing Rails project: 1) develop a shared vision with your team, 2) start with what’s easiest, then 3) expand your test coverage.
Develop a shared vision
Going from no tests to decent test coverage is unfortunately not as simple as just deciding one day that from now on we’re going to write tests.
The team maintaining the codebase needs to decide certain things, like what testing tools they’re going to use and what testing approach they’re going to use.
In other words, if the team wants to go from point A to point B, they have to decide exactly where point B is and how they intend to try to get there.
Start with what’s easiest
When adding tests to a codebase that has few or no tests, it might seem logical to start by adding tests where tests would be most valuable. Or it might seem logical to require all new changes to have tests. Unfortunately, both these ideas have problems.
The features in an application that are most valuable are also likely to be among the most non-trivial. This means that tests for these features will probably be relatively hard to write due to the large amount of setup data needed. Code written without testability in mind can also be difficult to test due to entangled dependencies.
Requiring all new changes to have tests also has problems. New changes aren’t usually independent of existing code. They’re usually quite tangled up. This brings us back to the same problem we’d have adding tests to our most important features: the setup and dependencies make adding tests difficult, sometimes prohibitively so.
What I would do instead is start with what’s easiest. I would look for the simplest CRUD interfaces in the app and add some tests there, even if those particular tests didn’t seem to add much value. The idea isn’t to add valuable tests right from the start but to establish a beachhead that can be expanded upon.
Once you have a handful of tests for trivial features, you can add tests for increasingly complicated features. This will give you a much better shot at ending up with good test coverage than trying to start with the most valuable features or trying to add tests for all new changes.
The mechanical details
If your existing Rails application doesn’t have any testing infrastructure, I would suggest taking a look at my how I set up a Rails application post. (Remember that it’s possible to apply an application template to an existing project.)
As you add tests to your project starting with the most trivial features, I would suggest starting with system specs as opposed to model specs or any other type of specs. The reason is that system specs are often more straightforward to conceive of and understand. If you’d like a formula you can apply to add system specs to almost any CRUD feature, you can find that here.
Then, as you get deeper into adding tests to your application, I would suggest two resources: Working Effectively with Legacy Code by Michael Feathers and my post about using tests as a tool to wrangle legacy projects. You might not consider your project a legacy project, but the techniques will be useful anyway.