Face it! No one really likes to do unit tests. A lot of people tell me how much they hate unit testing. While some people are good at it, for most of us, unit testing is a necessity, no matter how much complaining or disgust there is. Today, I’ll look at some of the reasons why we don’t like unit testing, and how to overcome those barriers through software automation.
So why unit tests?
Most development teams would agree that, although they don’t like it, unit testing is actually valuable. It helps developers really understand the code they are developing and provides a solid foundation for continuous testing of the pyramid (shown below), enabling teams to speed up agile development while reducing the risk of defects slipping into the later stages of the development pipeline.
I would go a step further and say that the process of creating unit tests is itself a beneficial activity that helps developers see their code in a different light, essentially conducting additional code reviews.
When unit testing, you can look at the interface of this feature from an external perspective and start with questions like “How do I use my code?” And so on. (simplifying the interface and reducing code maintenance costs), or what if I receive invalid data? (Leads us to write more robust and reusable code).
Why is such an important unit test so unpopular?
Often, development teams conduct little or no unit testing, usually due to a combination of (1) the pressure to provide more and more functionality (and time spent), and (2) complexity and time — the consuming nature of creating valuable unit tests.
This comes down to some common reasons developers cite for limiting the adoption of unit testing as a core development practice, including:
- Difficult to understand, initialize, and/or isolate the dependencies of the unit under test.
- Determining what to validate and defining the appropriate assertions is time consuming and often requires smart guesswork.
- There is a lot of manual coding involved, often even more than is required to implement a particular feature or enhancement.
- Just not as much fun… Developers don’t want to feel like testers; they want to spend their time delivering more functionality.
To address these limitations, several tools exist to help with unit testing. The unit test and assertion framework provides a standardized execution format (i.e., Junit) for seamless integration into the CI infrastructure (e.g., Jenkins, Bamboo, TeamCity). Ides help to create test code (for example, Eclipse, IntelliJ). A mock framework isolates code from its dependencies (for example, Mockito, PowerMock). Code coverage tools give you some insight into the code being executed (Emma, Cobertura, Clover, for example). The debugger allows developers to monitor and inspect the step-by-step execution of individual tests.
Unfortunately, all of these tools have limitations, and developers still find many difficulties, such as:
- The IDE helps create a framework for unit tests, but there is no “content.” Developers still need to add a lot of code to create execution tests:
- Assertions need to be defined manually, and tests must be performed to see if the correct values have been asserted.
- Simulation frameworks require a lot of manual code to instantiate and configure, as well as knowledge about how to use them properly.
- Coverage tools have insight into what code is covered by executed tests, but not into the runtime behavior of the tests.
- The debugger can be used for a single test, but cannot be extended to monitor the entire test run.
In summary, the creation of unit tests still requires a lot of manual, time-consuming, and often convoluted work before you can start adding business logic to your tests.
How to solve the problem? We “hired” an assistant!
We found that Parasoft Jtest’s unit testing assistant made unit testing less painful. After all, even though we hate unit testing, we know that the value it brings us far outweighs the trouble it causes. So long pain is better than short pain!
To help us work around these pain points, we started evaluating software test automation tools. You can now use Parasoft Jtest’s unit test assistant to solve these problems by creating fully functional unit tests with the click of a button.
Tests created using UTA are just “regular” JUnit, but it does all the tedious work for you. UTA sets up the test framework, instantiates the objects, and configures the emulation for the appropriate objects and method calls to be used by the method being tested.
These junits can be executed as part of a standard CI workflow, just as existing tests are executed. However, when UTA executes JUnit (including your existing tests), monitoring the tests in a way that not only provides code coverage, but also provides analysis capabilities.
By analyzing tests at run time, UTA can provide a series of recommendations, many of which have quick fixes to help you perform one-click actions, such as:
- Highlight object values that have changed and should be declared,
- Determine which method calls should be simulated to better isolate the code under test, as well
- Find tests that cannot be “cleaned up” automatically and create potentially unstable test environments (for example, due to the use of threads, external files, static fields, or system properties).
We use UTA to ease the pain of unit testing because, as a coder team specializing in software development and project customization solutions for more than 10 years, we know unit testing is an important step in creating safe, secure, reliable, and high-quality software.
If you have the same concerns and worries as me, please leave a comment. Of course, if you have tried better unit testing methods, please share them with me.