Working on legacy projects is a great opportunity to learn, but it might bring a headache or two, specially when it comes to testing.
We recently started on a project created by another company that doesn’t exist anymore. Just mentioning the term ‘legacy’ is more than enough to strike fear in the heart of even the most seasoned developers, and it’s well justified, for a very long number of reasons.
In this post, I’ll focus on the testing aspect of dealing with legacy projects, trying to show how to deal with it based on our experience, keep your sanity, live to tell the story, and have a happy client.
Adapt to survive
This one is a bit obvious, but if the project has already a test suite working, we’re going to need to adapt to it, even if it uses MiniTest instead of our beloved Rspec. There’s no easy and fast transition between different test gems, and it would take way too much time to translate all existing tests, so (unless there are almost no tests) it is just not worth it.
Get the docs, learn how they work, and crack on.
Baby steps, one at a time
This basic principle applies in every situation when it comes to testing. When we need to add a new functionality, we add tests one at a time, until we have the expected behaviour of our code.
When we are modifying the behaviour of, for example, a controller that has no tests at all, things change a bit. We’ll have to put in some extra effort and add some basic tests too. For a controller, they might the basic tests that assert a 200 response for GET requests, or the redirections. And then, of course, the tests that affect the behaviour we are modifying.
The idea is to lay the basic tests foundation in reverse, but at the same time, to be practical and not doing it all at once. Most probably you will revisit that controller in the short future, and surely you’ll have to add a new “test that should already be there” and tests for new features, so keep calm and arm yourself with patience, this is a long distance run. As a rule of thumb: “add the test for an existing behaviour when you change that behaviour”.
On the plus side, you’ll find that sometimes writing tests for stuff that already works can be a good way to get to know the system better and deeply than just by reading the code.
Bend it to your will
To keep sane and productive, you’ll write tests following your preferences and looking for efficiency. The following is a particular case, but it serves to illustrate this.
We’ve been working on a legacy project that relies mostly on Cucumber feature tests, and has tests in the models and some tests in services, but is very thin on controller tests. Cucumber is great for outlining scenarios and have features written in human-readable text, but running a whole test suite in Cucumber sure is very, very, slow.
Here at Cookies HQ we love testing our controllers, so we decided to go a bit easy on the feature tests and only use them in very particular cases, mostly revolving around Javascript working on the view when the user does something, and in exchange, build strong tests suites for our controllers and pay some extra attention at our model tests.
With this, not only we test things “our way” (so to speak), we also gain speed when running tests, so we can work and advance faster and more efficiently.
Of course, you should be careful when doing this kind of thing, and have into account that perhaps your company is not the only one working on the project, and in that case, ideally, some agreement should be reached. But in any case, pragmatism and the final goals (a working project and a happy client) should prevail.
Photo by Dennis Larson on Flickr