Choosing test values when writing unit tests is mostly guided by the need to cover all cases of the program logic. However, some values are better than others. Here are a few tips on how to pick values that make mistakes easy to spot and the tests easy to read. Plus a bonus tip on a quick way to double check your tests.
1. Make mistakes obvious. Suppose you have a function that subtracts one number from another, then using 20 – 10 = 10 is not so great. If there is a mistake in your code, and you simply return the second argument (10), it will still look like 20 – 10 gives the correct result. It is better to use for example 20 – 11 = 9. That way, the test would fail if the second argument is returned instead of the difference. This is a simple example, but the principle applies for more complicated cases as well.
2. Unused values. If there is a calculation test with four input values, but only three are used under some circumstances, then set the unused value to something that will stick out if used. Maybe the three used ones are 800, 300 and 100. Then don’t set the unused value to any of those. Instead make it something that will definitely alter the result if used, for example 555.
3. Easy to tell apart. There are two values used in a calculation, exposure and collateral. If you set the exposure to 1000000 and the collateral to 100000, they are not easy to tell apart when skimming the tests. If you want the exposure to be one million, then pick a collateral value that contrasts, for example 222000. At least now they are easy to tell apart at a glance.
4. Realistic values. Setting a currency code to XXX in a unit test will often work. However, you fail to show the next reader of the test how the code is actually used. By using for example USD, EUR or JPY as the currency code, you give a small example of a realistic use of the code. Also, if later on some validation code has been added for allowed currency codes, then you don’t need to modify the test case, since it already has an allowed value.
5. Test what shouldn’t happen. If you have code that should check if a string has an allowed value “localhost“, it is natural to write the test that matches. However, it is easy to forget to also test that, for example, “localhos” does not match.
6. Make sure it fails. When all tests for the new functionality are in place, it can be good to temporarily comment out a part of the new logic and make sure some of the tests fail. This is a quick insurance that the tests don’t always pass, but instead detect when the logic doesn’t work.
The examples above are simple and use mostly numerical values, but the same principles apply for more complicated cases and other types of input as well. Yes, you can write unit tests that work without considering any of the above tips. However, paying attention to the values you use for the tests will make the tests just a little bit more robust, and just a little bit easier to read. What other examples are there of test values that make the unit tests better? Let me know in the comments.
You can skip “Make sure it fails” step if you write unit tests before writing actual code 😉
Yes, good comment! Typically I do this step when there has been a lot of back and forth – as I code I realize cases I have forgotten, and I modify the tests and the code to account for that. In those cases I like to check in the end that the test does what I think it does.
Good tips. With regards to choosing values to pass into your unit tests, most of the time I use randomly generated values. It curbs the chances of your tests giving false positives.
Pingback: Java Weekly, Issue 366 | Baeldung