23

When writing unit tests, is it worth spending the extra time to make the code have good quality and readability?

When writing tests I often break the Law of Demeter, for faster writing and to avoid using so many variables. Technically, unit tests are not reused directly - they are strictly bound to the code so I do not see any reason for spending much time on them; they only need to be functional.

3
  • 6
    Readability and maintainability needs to be primary focus of unit testing.
    – Yusubov
    Commented Jun 27, 2012 at 13:50
  • 3
    Tests are code too! Commented Jun 27, 2012 at 15:37
  • It is still part of your project, even if it doesn't get shipped to customers. Treat it accordingly.
    – user1249
    Commented Sep 17, 2012 at 11:08

7 Answers 7

11

You should definitely take the same if not better care of your unit tests than your production code in terms of quality and readability. The unit tests are often the first thing you look at when trying to grasp what some piece of code does, and the reader should quickly understand what's at stake when looking at the test. Unit tests also tend to change a lot and will break a lot if their design is not robust, which kind of nullifies the benefits of having tests.

Violation of the Law of Demeter is definitely a problem in your unit tests for that reason as well as 2 others that come off my mind :

  • If your tests break the Law of Demeter in their Arrange or Act sections, it's probably a sign that your production code also does, since your unit tests are just another consumer of your code and will probably call and operate the class under test in the same way that any other production code would do.

  • If your tests break the Law of Demeter in their Assert sections (ie you verify the value of something that is deeply nested in the dependencies graph of the object under test), it might be that those are really integration tests rather than unit tests. In other words, if in TestA you assert that A.B.C.D equals something, it might be that you're actually trying to test D and A rather than just A.

By the way, when you say

I break very often the Law of Demeter, for faster writing and not using so many variables.

you should be aware that writing

var grab = myDependency.Grab;
var something = grab.Something;
var very = something.Very;

very.Deep();

is actually no better Demeter wise than

myDependency.Grab.Something.Very.Deep();

if that's what you meant.

48

It is absolutely worth spending time writing good-quality code for unit tests:

  • They will require maintenance like any other code.
  • Unit tests are one of the best sources of documentation for your system, and arguably the most reliable form. They should really show:
    • Intent: "what is the expected behaviour?".
    • Usage: "how am I supposed to use this API?".
  • They will require debugging like any other code.

The one factor in favour of a slightly more ad-hoc approach is that your unit tests are never going to be a public API so you don't need to worry about what interfaces/etc. you are exposing.

23

Yes, it matters. There are several reasons why unit tests should be held to a comparable standard as other code:

  • Each unit test also serves as documentation for the testee. When the tests are comprehensive and cover as many edge cases and error conditions as possible, they can often replace the comment-documentation of a class or function. They can also serve as a starting point for people new to the code base.

  • Unit tests can be buggy, too. And errors are more visible when the code is well written.

  • If, for some reason, you later need to split up a module, you'll probably need to split up its unit tests, too. This is easier if the tests are written such that they have easily discernible dependencies.

That said, there's always the question of practicality. Depending on the language and nature of your code, it can be hard to write "clean" unit tests without spending much more time on the tests than on the code they are supposed to test. In that case, I usually fall back on testing the easy, quick stuff and the most critical functionality, without worrying too much about complete coverage. Whenever a bug crops up at a later point, I write a test for it and check if I can refactor the new test and existing ones to make them nicer.

12

if you cannot read a unittest and find out what it is testing the next time it fails you'll spend double the debugging time (once to find out what the test is about and once to fix the code it is testing)

honestly unittests should have a expected outcome; do procedure; get actual outcome; test expected against actual type of structure which is easy to write and understand

1

The test code should receive just as much love as your production code. For readability, maybe even more. If anyone else than you(including you two weeks after leaving the code) is supposed to understand what is going on, then you should make your code nice an crisp.

This means:

  • Extract building of test data into builder classes.
  • Extract multible assertions into separate assertion methods.
  • Be very precise in your naming. Assert.That(x4, Is.EqualTo(y16*2*SOME_VALUE), ASS_ERR_TXT_56) makes very little sence to most readers.

Taken to the extreme, tests can be written so they are almost as easy to read AND understand as prose. The extreme tester would probably say that a unit test more than 10 lines long is a bad one.

1

The most important practical reason is that every time you change code, you change unit tests. And if you're doing TDD, you're even changing the unit tests first.

Do either of these things in your tests:

  • Duplicate code
  • Diminish readability
  • Tight coupling
  • Temporal coupling
  • High cyclomatic complexity (lots of dependencies)

And you're in for a whole lot of work when a change is needed.

Treat your tests like you suggested, and you'll end up regretting it. You'll probably even reach the false conclusion that "TDD doesn't work".

0

It depends on whether these unit tests are "temporary" or not. If

  1. Test will be frequently used;

  2. Developers have to work with unit tests written by other developers;

  3. Most of the testing is done by unit tests

then the tests should be written properly. In case there is a bug in the test itself, it will be difficult to find the bug and fix it, especially if some time has passed since the test was written.

On the other hand, if these tests are used only by the developers himself/herself only, than I think its ok. But still it is more preferable to write 'readable' code. As ratchet freak said, you'll have spend more time fixing your tests than you would spend on writing them properly.

1
  • (1) unit tests are never temporary (2) even if they are for your self, in one month (or more), you will not remember all details, therefore it is important to do it properly - even for yourself Commented Jan 9, 2014 at 9:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.