Take the 2-minute tour ×

I ruined several unit tests some time ago when I went through and refactored them to make them more DRY--the intent of each test was no longer clear. It seems there is a trade-off between tests' readability and maintainability. If I leave duplicated code in unit tests, they're more readable, but then if I change the SUT, I'll have to track down and change each copy of the duplicated code.

Do you agree that this trade-off exists? If so, do you prefer your tests to be readable, or maintainable?

share|improve this question
add comment

11 Answers

up vote 19 down vote accepted

Duplicated code is a smell in unit test code just as much as in other code. If you have duplicated code in tests, it makes it harder to refactor the implementation code because you have a disproportionate number of tests to update. Tests should help you refactor with confidence, rather than be a large burden that impedes your work on the code being tested.

If the duplication is in fixture set up, consider making more use of the setUp method or providing more (or more flexible) Creation Methods.

If the duplication is in the code manipulating the SUT, then ask yourself why multiple so-called “unit” tests are exercising the exact same functionality.

If the duplication is in the assertions, then perhaps you need some Custom Assertions. For example, if multiple tests have a string of assertions like:

assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())

Then perhaps you need a single assertPersonEqual method, so that you can write assertPersonEqual(Person('Joe', 'Bloggs', 23), person). (Or perhaps you simply need to overload the equality operator on Person.)

As you mention, it is important for test code to be readable. In particular, it is important that the intent of a test is clear. I find that if many tests look mostly the same, (e.g. three-quarters of the lines the same or virtually the same) it is hard to spot and recognise the significant differences without carefully reading and comparing them. So I find that refactoring to remove duplication helps readability, because every line of every test method is directly relevant to the purpose of the test. That's much more helpful for the reader than a random combination of lines that are directly relevant, and lines that are just boilerplate.

That said, sometimes tests are exercising complex situations that are similiar but still significantly different, and it is hard to find a good way to reduce the duplication. Use common sense: if you feel the tests are readable and make their intent clear, and you're comfortable with perhaps needing to update more than a theoretically minimal number of tests when refactoring the code invoked by the tests, then accept the imperfection and move on to something more productive. You can always come back and refactor the tests later, when inspiration strikes!

share|improve this answer
"Duplicated code is a smell in unit test code just as much as in other code." No. "If you have duplicated code in tests, it makes it harder to refactor the implementation code because you have a disproportionate number of tests to update." This happens because you are testing the private API instead of the public API. –  user11617 Jan 18 '13 at 14:39
add comment

Readability is more important for tests. If a test fails, you want the problem to be obvious. The developer shouldn't have to wade through a lot of heavily factored test code to determine exactly what failed. You don't want your test code to become so complex that you need to write unit-test-tests.

However, eliminating duplication is usually a good thing, as long as it doesn't obscure anything. Just make sure you don't go past the point of diminishing returns.

share|improve this answer
xUnit and others contain a 'message' argument in assert calls. Good idea to put meaningful phrases to allow devs to quickly find failed test results. –  seand Mar 31 '12 at 2:12
@seand You can try to explain what your assert is checking, but when it's failing and contains somewhat obscured code then developer will need to go and unwind it anyway. IMO It's more important to have code to be self-describing there. –  IgorK Oct 6 '12 at 23:24
add comment

Implementation code and tests are different animals and factoring rules apply differently to them.

Duplicated code or structure is always a smell in implementation code. When you start having boilerplate in implementation, you need to revise your abstractions.

On the other hand, testing code must maintain a level of duplication. Duplication in test code achieves two goals:

  • Keeping tests decoupled. Excessive test coupling can make it hard to change a single failing test that needs updating because the contract has changed.
  • Keeping the tests meaningful in isolation. When a single test is failing, it must be reasonably straightforward to find out exactly what it is testing.

I tend to ignore trivial duplication in test code as long as each test method stays shorter than about 20 lines. I like when the setup-run-verify rhythm is apparent in test methods.

When duplication creeps up in the "verify" part of tests, it is often beneficial to define custom assertion methods. Of course, those methods must still test a clearly identified relation that can be made apparent in the method name: assertPegFitsInHole -> good, assertPegIsGood -> bad.

When test methods grow long and repetitive I sometimes find it useful to define fill-in-the-blanks test templates that take a few parameters. Then the actual test methods are reduced to a call to the template method with the appropriate parameters.

As for a lot of things in programming and testing, there is no clear-cut answer. You need to develop a taste, and the best way to do so is to make mistakes.

share|improve this answer
add comment

I agree. The trade off exists but is different in different places.

I'm more likely to refactor duplicated code for setting up state. But less likely to refactor the part of the test that actually exercises the code. That said, if exercising the code always takes several lines of code then I might think that is a smell and refactor the actual code under test. And that will improve readability and maintainability of both the code and the tests.

share|improve this answer
I think this is a good idea. If you have a lot of duplication, see if you can refactor to create a common "test fixture" under which many tests can run. This will eliminate duplicate setup/teardown code. –  Outlaw Programmer Sep 24 '08 at 21:34
add comment

You can reduce repetition using several different flavours of test utility methods.

I'm more tolerant of repetition in test code than in production code, but I have been frustrated by it sometimes. When you change a class's design and you have to go back and tweak 10 different test methods that all do the same setup steps, it's frustrating.

share|improve this answer
add comment

Ideally, unit tests shouldn't change much once they are written so I would lean towards readability.

Having unit tests be as discrete as possible also helps to keep the tests focused on the specific functionality that they are targeting.

With that said, I do tend to try and reuse certain pieces of code that I wind up using over and over, such as setup code that is exactly the same across a set of tests.

share|improve this answer
add comment

"refactored them to make them more DRY--the intent of each test was no longer clear"

It sounds like you had trouble doing the refactoring. I'm just guessing, but if it wound up less clear, doesn't that mean you still have more work to do so that you have reasonably elegant tests which are perfectly clear?

That's why tests are a subclass of UnitTest -- so you can design good test suites that are correct, easy to validate and clear.

In the olden times we had testing tools that used different programming languages. It was hard (or impossible) to design pleasant, easy-to-work with tests.

You have the full power of -- whatever language you're using -- Python, Java, C# -- so use that language well. You can achieve good-looking test code that's clear and not too redundant. There's no trade-off.

share|improve this answer
add comment

I LOVE rspec because of this:

It has 2 things to help -

  • shared example groups for testing common behaviour.
    you can define a set of tests, then 'include' that set in your real tests.

  • nested contexts.
    you can essentially have a 'setup' and 'teardown' method for a specific subset of your tests, not just every one in the class.

The sooner that .NET/Java/other test frameworks adopt these methods, the better (or you could use IronRuby or JRuby to write your tests, which I personally think is the better option)

share|improve this answer
add comment

Jay Fields coined the phrase that "DSLs should be DAMP, not DRY", where DAMP means descriptive and meaningful phrases. I think the same applies to tests, too. Obviously, too much duplication is bad. But removing duplication at all costs is even worse. Tests should act as intent-revealing specifications. If, for example, you specify the same feature from several different angles, then a certain amount of duplication is to be expected.

share|improve this answer
add comment

I don't think there is a relation between more duplicated and readable code. I think your test code should be as good as your other code. Non-repeating code is more readable then duplicated code when done well.

share|improve this answer
add comment

Unit tests ideally shouldn't take a long time to run so even if there is a duplication rerunning all of them should be able to tell you which ones to change within a reasonable amount of time.

share|improve this answer
Could you elaborate? I don't understand what you mean. –  Daryl Spitzer Jun 25 '11 at 0:17
1) Run all your unit tests after a change. 2) Any test that fails due to a source code change will need to be investigated. 3) If the tests run in a few minutes not hours this approach might work. –  Sid Jagannathan Jun 30 '11 at 5:59
add comment

Your Answer


