This blog has been archived. Our writing has moved to makandra cards.
The blog of , a Ruby on Rails development team

When to repeat yourself in tests - and when not to

DRY – Don't Repeat Yourself – is one of the first techniques a developer needs to master. After a while DRY becomes so primal to a programmer's thinking that she cringes whenever she sees that principle violated.

When the same programmer learns test driven development, she will be surprised at the level of apparent duplication going on. Seeing the same piece of logic touched by separate unit tests, controller tests and integration tests will seem horribly wrong. But a reasonable level of repetition in your tests is actually a good thing.

First, different kinds of tests do not actually test the same thing. They look at your code through different lenses, some narrowly focused, some gazing at the broader picture. Combining those different points of views allows a much richer description of your code. It also makes your test suite more brittle, often resulting in multiple tests failures after a single code change. This tradeoff has a sweet spot.

Sometimes an additional type of test does not add value beyond what other types of tests already cover. For example, we often find the combination of unit and integration tests to be sufficient to describe a given feature. Supplementing controller and view tests for the same feature would add little coverage for the amount of code they impose on the project. In that case these tests can and should be omitted. It takes a little experience to know when to cut corners this way. When in doubt, write the test.

There is another reason why some repetition in your tests is OK: Your tests are not supposed to be too clever. Clever things should happen in the code your tests are cross-checking. When tests gain complexity through nested method calls and metaprogramming magic, they themselves become a cause of defects.

Some people go as far as to not use even basic helpers, like routes, in their tests. They'd rather type out an URL as a string than call the router. We find such purism to be impractical. Your tests should be able to call code that is tested elsewhere. For example, when a complex route requires further description, this can be covered by a dedicated test. This way your other tests don't need to repeat details outside their focus.

Growing Rails Applications in Practice
Check out our e-book:
Learn to structure large Ruby on Rails codebases with the tools you already know and love.

Recent posts

Our address:
makandra GmbH
Werner-von-Siemens-Str. 6
86159 Augsburg
Germany
Contact us:
+49 821 58866 180
info@makandra.de
Commercial register court:
Augsburg Municipal Court
Register number:
HRB 24202
Sales tax identification number:
DE243555898
Chief executive officers:
Henning Koch
Thomas Eisenbarth