In this article, you get one single checklist that guides you through the whole unit testing process. By going through all the individual steps of this checklist, you can ensure that you don’t waste any more time on creating unit tests inefficiently, or having to throw away unit tests because you cannot maintain them after some months after the project has started.
Before writing any code, you have to define which test cases you need (so what part of the software should be tested, what are positive/negative cases, and how should the software behave in these cases). Based on this information, you can think about the most effective test cases for your considered code unit.
Equivalence class partitioning and boundary value analysis provide optimal guidance for the above-mentioned steps (learn these techniques using this article: 2 methods that help you save 60 % of your effort in Unit Testing). To identify the correct scope for every defined unit test, you can make use of the FIRST principle (As described in this article: Clean Unit-Testing, What it takes to make good Unit-Tests).
How this principle can be implemented in practice is shown in the following article: Good Unit Tests VS Bad Unit Tests (with C# and NUnit Examples)
So, in summary, simply fill out the following checklist to ensure maximum productivity during test case definition:
1.1: What code unit(s) do you want to test?
1.2: For every code unit: what are positive/negative cases?
1.3: Write down one equivalence class for every positive/negative case.
1.4: For every equivalence class: what are the boundary values?
1.5: What are unit tests that consider all boundary values, based on the FIRST principle?
After defining unit tests, you have to write code that implements these unit test cases. This step shows you whether you have planned out everything correctly in the previous steps, or you have to go back and refine your test cases. However, even after you have implemented your test cases successfully, what happens if you have to change a unit test after two months? Do you still know where to perform the test? Do you even find that unit test any more? Or do you rather accept your test base as a code graveyard that you don’t want to touch any more? In other words: you want to write maintainable unit test code! The key to do so efficiently are design patterns (such as arrange-act-assert: The AAA Test Pattern explained with C# and NUnit) and naming strategies. Using the test code creation part of this checklist, you can make sure that you stick to these best practices.
2.1: What is your naming strategy for test classes?
2.2: Based on this naming strategy, and the test cases defined in step 1.5: which test classes do you need for your project, and what are their names?
2.3: Do your implemented test classes match the description in step 2.2?
2.4: What is your naming strategy for unit tests?
2.5: Based on this naming strategy, what is the name for every unit test defined in step 1.5?
2.6: For each unit test: in which test class should it be implemented?
2.7: Does every implemented unit test have a clearly defined (annotated with a code comment) Arrange section?
2.8: Does every implemented unit test have a clearly defined (annotated with a code comment) Act section?
2.9: Does every implemented unit test have a clearly defined (annotated with a code comment) Assert section?
2.10: [Double-Check] Do you have a unit test implemented for every test case derived from the equivalence classes in step 1.5?
2.11: [Double-Check] Does the name of every unit test match the name defined in step 2.5?
A checklist that makes sure that you have good naming strategies in place, and improve them over time, can be found in the following article: A Checklist for Assessing the Quality of your Unit Tests
After writing your unit tests, you want to make use of them. However, most people only think about unit tests as a way to find bugs in their implementation. But there are more ways to make use of your unit tests after their implementation, as detailed in this article: 5 things you can learn from executing your test cases.
These aspects are all reflected in the following checklist points:
3.1: if you adapt the functionality of some part of your system, does all unit tests still pass? If answered yes, you have to add more tests!
3.2: After some code refactoring: do all unit tests still pass? If answered no, you have done your refactoring wrong!
3.3: Does running the same unit test on the same version of the code unit yield different results? If answered yes, you have to adapt the implementation of your test case!
3.4. Do you have test cases that always fail together (if one test case fails for a certain version of the code, the other one also fails)? If answered yes, you can most probably delete one of these tests!
3.5: Which of your unit tests fail often? Make these test cases part of your regression test suite!
3.6: Are there noticeable changes in the execution time of the same test suite for different test runs (tests run a lot faster or slower than usual)? If answered yes, have a look at whether the tested system has some problem that is not detected by your unit tests!
By using this checklist, you should be able to maximize your unit testing productivity. Please use the comments section below to let me know about your experiences, or any suggestions that you have!
When you visit any web site, it may store or retrieve information on your browser, mostly in the form of cookies. Control your personal Cookie Services here.