Properties of a Good Unit Tests
Question: what are the properties which make a test a good unit test? If you have a good answer, check out my answer and add to it in the comments. If you don’t here is mine.
Long Descriptive Name: For example returnsNullWhenCalledOnEmptyList is a nice name for a test
Simple Clean Structure: A test performs necessary setup, executes the method to be tested and performs its assertions. Not more not less
Fast: one thousand tests should run in less than a minute. This allows an extensive test suite to run often during development. If your tests are slower, you might be doing integration tests.
Test a Single Feature or behavior: This is sometimes phrased as ‘one assertion’, which I consider misleading. If you need multiple assertion in order to assert one behavior thats OK, although you might consider a new assert method for that.
Reliable: For the same code base a test should produce the same result every time. A test that fails every 10th time will fail for a real bug and you won’t know it.
Stable: The test only fails, when the code under test doesn’t behave as expected, not because anything else changed.
Easy to Understand: Just as normal code, the intention of a test should be easy to understand. Names help with this. Extracting setup code in a properly named method helps as well.
Should Not Use Production Classes, Except The Class Under Test: This helps with the ‘Stable’ and the ‘Fast’ property. It’s ok to use simple classes like String or Integer.
Don’t Try to Squeeze All Tests for a Class in a Single Test Class: For many classes you will have more then one test class. The different test classes will probably differ in the setup needed for the contained tests.
Independent: No Test should depend on any other Test or on the order of execution.
Hi,
Absolutely, but some additions:
I think this is even too long. In an IDE runner, a thousand tests should not take not longer than 5s. An efficient code-test-fix-cycle should be as fast as possible. waiting for a test suite to finish will drastically reduce the motivation to do TDD.
An even stronger requirement: A test has to be deterministic. This means no random, no new Date() or whatever.
And finally, what i think is most important: A test has to be maintainable. This means refactoring a system under test should yield in efficient and small changes in the test. This could be a realized by finding a proper abstraction level even within test classes. in additional this will also result in even more readable code.
Couple additions:
- test code should be “clean” and treated just like production code. The understandability of test code is just as important as production code as it must be maintained and is vital to integrity of the product
- test should cover boundary cases and attempt to gain optimal code coverage. It should cover all (most) paths
- Practicing TDD (test first) should produce tests that are less brittle and focus on testing the behavior of the code and not be dependent on the structure. However, unit tests, due to mocks will be dependent on implementation up to a point certainly.
[...] Properties of good unit tests – check how many properties your test have. [...]
Hello,
nice post. My 3 cents below.
>Long Descriptive Name: For example returnsNullWhenCalledOnEmptyList is a nice name for a test
I think it fits very nicely int “test behaviour not methods” approach.
>Fast: one thousand tests should run in less than a minute. This allows an extensive test suite to run often during
>development. If your tests are slower, you might be doing integration tests.
Agreed with Lars – one minute is probably too long.
>Should Not Use Production Classes, Except The Class Under Test: This helps with the ‘Stable’ and the ‘Fast’ property. It’s
>ok to use simple classes like String or Integer.
In general yes …but sometimes no. I mean, testing in isolation is very important or even crucial, but some classes simply goes together with other classes. And there is no point in mocking them then. It especially goes for “value objects” (to use term from mock objects book by Nat Pryce and Steve Freeman).
>Independent: No Test should depend on any other Test or on the order of execution.
There is one form of dependency that I like and allow. For example you can say something like: “ok, I have this class, and I test it. Now, if the test for constructor does not pass, there is no point in running other tests for this class, because it is probably in the wrong state anyway.” TestNG helps you do it in a nice way. It is more important for the integration tests thought – e.g. no need to try to run a test that fetches some values from server if the connection test didn’t pass.
–
Cheers,
Tomek Kaczanowski