“Unit tests”. Even the sheer mention of the words can send shivers down the most veteran developers’ spines and recall memories of unrelenting QA engineers. Okay, enough with the drama! Just tell your developers they are going to write them and they don’t have an option.
Time invested into writing unit tests should never be deemed as time wasted. In fact, it should be viewed as just the opposite: time saved. As a former rejecter of writing unit tests, it only took one large scale project to radically reverse my views and accept unit tests for what they are: time savers and debugging assisters. The best thing about the adoption of unit tests is the utter fact that it is never too late to begin writing them. The simple selection of an open source testing framework will instantly begin enhancing the quality of your company, team, or project’s solutions.
It is important to note that writing unit tests does not always provide an immediate return. In fact, I would argue that a strong developer equipped with his favorite debugger can produce initial code just as fast, or faster, than one who opts to develop against unit tests. A return is shown only when the special function gets modified halfway through the project, or the core entities backing your object hydration need refactoring, or that annoying stored procedure gets optimized by the DBA, or, my personal favorite, the database platform is entirely uprooted for another option.
That strong developer who rejects unit tests approaches the scenario of modifying months old code with two possible methods: the jaw dropped to the floor or quick trip to the nearest gas station for some red bull because he/she will be spending an overnighter in the office. The unit test adopter has one approach to the same scenario: he frowns a little for having to re-factor code, but upon completion smiles because all he has to do is click “Run Tests” to guarantee the change is successful.
Revisiting what was said earlier, the strong developer can produce working initial code most likely faster than code backed by unit tests. This is obviously due to time spent writing these tests; however, the amount of time spent debugging or recalling all of the test scenarios far exceed the initial investment. For this reason, I advocate writing the implementation prior to unit tests. Following the steps below have personally kept me at my peak productivity throughout my active project.
Choose a testing framework to write unit tests against. As a C#/.NET specialist, I elect to use nUnit.
Determine a universal guideline for your company, team, or project to follow with regards to unit tests.
How thorough are you going to write your unit tests?
What code coverage percentage are you looking for? (Discussed later)
ITERATIVELY implement functions of your application followed by your unit tests.
As a back-end developer, I often will implement a significant chunk or segment of a service and then follow it up with the unit tests.
Personally, I write unit tests to cover all possible code paths and parameter scenarios. While this is not the industry standard, be sure to utilize this step to follow the universal guidelines set forth for the project. You do not want half of your application to have 100% code coverage and the other half have 50% coverage. Consistency has a direct correlation to quality.
Do not significantly advance your implementation until all of your unit tests pass.
That wasn’t so bad, now was it? But wait … there is more. You can use your unit tests to leverage more out of your solutions. The first is code coverage reports. Code coverage is a measure used to determine what percentage of your implementation is hit at some point by a unit test. A code coverage framework will simply read in a class library that has test fixtures in it and generate a report. The second, and personally my favorite, is Continuous Integration.
Let us do the heavy lifting.
Are you ready to start a new software development project? Work with our local team of software designers and developers or let us help you recruit a team of your own.
Continuous Integration is a concept in which you will iteratively run your unit tests against code throughout your development process. The most widely accepted trigger for continuous integration builds is a simple source control check-in. EVERY TIME code is committed to your repository, it should run the new build against your unit tests. This enables you as a project manager or developer to guarantee that at any time, you can release a revision into the production environment. If your check-in causes the continuous integration server to fail the build, you should STOP what you are doing and fix the build prior to continuing. If you ignore a broken build, you are throwing away all of the time you invested into writing these unit tests in the first place. Lastly, common sense suggests that you should NOT deploy a build or code base that does not build against your continuous integration server. It does not matter if the unit tests pass on your mid-level developer’s computer; it is NOT good enough. With the complexity of operating systems and software these days, environments play too much of a factor into why some deployments go bad.
In summary, unit tests have increased the productivity in our team by keeping us fixing broken code instead of debugging it. Continuous Integration has kept our team up to date by the minute as to whether or not we can release a new revision of our solution into production should the need arrive. The investment spent writing the unit tests were justified on more counts than can be remembered. There truly is no way to know if a complex system will continue to work properly when integrated components are re-factored late in the project without strong unit tests in place to assist.