Unit Test Insanity
Are you repeating your unit tests in an effort to expect a different result?
Join the DZone community and get the full member experience.Join For Free
While moving our daughter into her new apartment, which happens to be on the 9th floor of the rental complex, I noticed an interesting situation while waiting for the elevator to arrive. As others walked up to wait for the elevator, they would push the button with the universal "arrow pointing up" symbol — even though we had already pushed the button to request the elevator's service.
I began to wonder about the thought process at play here. Did the person feel like the elevator would arrive quicker if the up button is pushed again? Was a different result expected?
You may also like: 7 Tips for Writing Better Unit Tests in Java
Believe it or not, this reminded me of something I call "unit test insanity."
Unit Test Insanity
Since I saw the value in writing my first unit test decades ago, I have always been an advocate of including unit test coverage in order to validate the functionality of the system under test (SUT). However, like nearly everything in Information Technology, there is an opportunity to over-build to the point where the value of such enhancements approaches zero.
In this article, I want to focus on the scenario where unit test coverage is added — which duplicates a suite of tests already in use. When this happens, the testing suite ends up performing the same test over and over again — as if a different result is expected.
In my "Avoid Reloading Application Context on Unit Tests" article in the Microservices Zone, I provided the following service class implementation example:
In this very simple example, before the List<Widget> can be returned, the
AccountService is called to provide some level of authorization/validation that the
authId has proper clearance to see widgets related to the provided
If proper clearance is not achieved, the
AccountService will throw an
AccountException. This exception is simply passed on to whatever is calling the
Unit Test Coverage
In the example above, when the
AccountService was introduced, the developer would have included unit tests which cover all aspects of the
Some unit test cases are listed below:
- A valid
authId, which has proper access to a valid
accountId, returning an
accountId, throwing an
authId, throwing an
AuthIddoes not have access to accountId, throwing an
With respect to the
getWidgetsByAccountId() method, there is certainly a need to mock the
AccountService and create a
when() case for when the
authId are valid values and an
Account object is returned.
An example of the very simple unit test may appear as follows:
In this example, there is really not a need to test the use cases which simply throw an
AccountException. This is because that result is not really part of the system under test (SUT) and is already assumed to be covered in the
When writing unit tests, it is always important to maintain a focus on testing only the system under test (SUT). In cases where the method being tested can be impacted by an exception being thrown by an injected service, that service exception does not need to be tested if the result of the exception merely forwards the exception to method calling the SUT. To me, doing so is an example of "unit test insanity."
The exception to this rule is when the dependent exception is caught and the flow of the SUT is altered. In this case, throwing the exception is necessary — just as valid mocked data is necessary — but the focus on the test should be to validate that the logic in the SUT is working as expected.
Have a really great day!
Opinions expressed by DZone contributors are their own.