Obviously. The point, though, is that you should use all of the principles you apply to writing good code in general when writing unit tests. You will need to maintain, fix, and improve tests over time just like all other code!
If you don’t follow best practices, updating tests will become such a nightmare that you will simply start deleting tests or just stop testing at all. Then regressions creep in and the game is over.
First, we need to identify what a given unit should do.
This sounds simple, but it isn’t!
We can easily create tests for the common, obvious cases, but we must also test for the boundary cases.
For instance, if we are implementing a function to calculate the area of a rectangle given its height and width, what inputs should we test?
First, we would do something obvious like area(10,5)=50.
But what happens if we are given negative values? What if we are given zeros?
We often forget about these types of inputs when writing code and just assume we will “obvious” inputs.
In this particular case, the logic is simple enough that we can easily address the problem with a couple of tests and some branching in our code.
In general, though, we really need to focus on our domains.
In general, for an integer parameter, we should probably consider the following values:
If we know we are using modular arithmetic, then we may want to test one representative from each congruence class as well.
If we are working with mod m, then maybe a good set of tests would be
-m-1, -m, …, -2, -1, 0, 1, 2, …, m, m+1
Basically, what you want to do is think about the input types, identify boundary values that are likely to cause different behavior, then test those boundary values, near those boundary values, and far away from the boundaries in all directions.
And don’t forget null values!
So what would good inputs be for a method with a List input?
What about a method that takes a Point as input?
What about String inputs?
Once we have decided what we need to test, we will write a single unit test for each interesting input and make an assertion about what its output should be.
Ideally, you should have one assertion per test. if not, all assertions should at least be testing one aspect of your code.
How can we test code that requires a database lookup?