Test-Along, if not Test-Driven
Many a times, rookies have been found to start writing unit tests once they have written most of the code, e.g., towards the end of the coding. However, to make the most of unit tests, one should write them as they write the code. This is somewhat different and less difficult than writing tests first and code later as in test-driven development (TDD). Following are some of the advantages of doing “test-along” development:
- One could achieve greater code coverage by writing all possible tests for testing functionality as per the requirement. Towards the end, one may end up missing one or more unit tests covering different use-case scenarios, thus, leading to test smells.
- It could be also prove to be very helpful in code refactoring as one could code change easily due to safety net provided by unit tests.
- Overall, this practice also propagates good unit testing practice in the team.
Unit Tests Naming
Traditionally, many a developers have been found to write unit tests corresponding to every single method in the class. This approach tends to miss out on one or more unit tests testing different use-case scenarios of same functionality. One o fthe primary reason is the naming style which propagates naming based on testXXX where XXX is method name. This could be improved by naming unit tests representing various different use-case scenarios and not just testXXX. In this manner, unit tests would also act as an alternate form of functional requirements documentation. With this approach, it would be helpful for developers to rather use unit tests to understand the code than the code itself.
Various different techniques have been suggested in this regard. Some of these techniques are listed below:
Testing Happy & Exception Paths
When reviewing unit tests code, I have come across various cases where unit tests have been written to test just the happy execution paths. To be able to write quality unit tests, one should cover both happy and exception-based/failure execution paths. This would as well increase test coverage.
Testing Different Execution Paths
If you have heard about lower code coverage, this is primarily due to the fact that many execution paths within a method to be tested is not tested. This leads to lower code coverage. To achieve a greater code coverage, one should write one unit test for each execution path. If the execution paths in a method are large, it is a sign that you may need to refactor the method and then write unit tests for new methods. One of the ways to count execution paths in a method is McCabe Cyclomatic Complexity using which one could count on different decision points that corresponds to execution paths.
Mocking enables testing a class in isolation when the class calls one or more classes. This is a pretty cool feature and helps developer avoid doing integration testing thereby testing several dependent classes. Some of the advantages of Mocking are following:
- One could verify interaction behavior
- One could verify number of interactions and also, those interactions that are never invoked.
- One could stub the method calls with pre-defined return