Now that we learned how to write tests with JUnit 5, let us focus on what makes a good unit test.
In this section, we will discuss the FIRST principles, as described in the book: Jeff Langr, Andy Hunt, and Dave Thomas, Pragmatic Unit Testing in Java 8 with JUnit, 2015.
Note: This book adopts JUnit 4. We will use it for good testing practices, which are applicable regardless of the version of JUnit you are using (or even your testing framework).
Unit tests provide many significant benefits when crafted with care, but your tests are also code you must write and maintain.
You and your team can lose lots of time with your tests because the tests:
A set of principles to avoid common pitfalls in unit testing:
It is fundamental that your unit tests are fast.
Fast tests:
Slow tests:
you will probably have a few thousand unit tests.
If an average test takes 200 ms, running 2500 unit tests takes 8 minutes
One should not expect from developers to run an 8-minute test suite many times throughout a day.
As your system grows, 8 minutes may easily become 15 or 30 minutes.
If it takes painfully long to run your test suite more than a couple of times a day, you’ve tipped the scale in the wrong direction.
Your test suite should provide continuous, comprehensive, and fast feedback about the health of your system.
Think of your course project. What can significantly slow down your tests?
Isolated tests have two main characteristics. They are focused and independent.
Good unit tests focus on a small chunk of code to verify.
When you start to add a second assertion to a test, ask yourself:
Does this assertion help to verify a single behavior, or does it represent a behavior that I could describe with a new test name?
If one of your test methods can break for more than one reason, consider splitting it into separate tests.
When a focused unit test breaks, it’s usually obvious why.
Good unit tests depend as little as possible on other unit tests.
The more code that your test interacts with, directly or indirectly, the more things can break it.
Tests that must ultimately depend on a database require you to ensure that the database has the right data.
Good unit tests also don’t depend on other unit tests (or test cases within the same test method).
You should be able to run any given test at any time, in any order.
A repeatable test is one that produces the same results each time you run it.
Repeatability often requires isolation.
Avoid the temptation of adding a random value to your tests.
double x = Math.random();
double y = Math.random();
Without repeatability, it becomes difficult to find the source of the problems.
Each test should produce the same results every time.
Tests are not useful if they do not assert that things go as expected.
You write unit tests to save you time, not to waste your time.
Your tests should never require manual setups before you can run them.
You must automate any setup your test requires.
You can write unit tests at any time, but you are better off focusing on writing unit tests in a timely fashion.
The more you defer writing tests, the more defects you will need to deal with.
Once you check code into your git, it is unlikely that you will come back and write tests for it.
Many dev teams have rules and mechanisms that enforce unit testing.