As Roy Osherove wrote in his book, The Art of Unit Testing, “Unit testing isn’t a new concept in software development. It’s been floating around since the early days of the Smalltalk programming language in the 1970s, and it proves itself time and time again as one of the best ways a developer can improve code quality while gaining a deeper understanding of the functional requirements of a class or method.”
Since unit testing plays such an important role in TDD, programmers must learn not only simply how to unit test, but the art of the code itself in order to becoming testing masterminds.
Properties of a proper unit test
All programmers in TDD and .net know the importance of your code properties in unit testing, however how many actually know what all of these properties are? While you’re given the tools to perform these various tests sometimes to learn the art of something it’s best to take a step back and look at if from the basics.
A unit test should include the following properties; it should be automated, repeatable, and easy to implement with other TDDs. Once the test has been written it should remain available for future .net programmers, or any programmer for that matter to use and anyone should be able to run it. Your unit test should run at the push of a button, and it should run quickly.
These may seem like rather obvious properties, but you’d be surprised how many people confuse the act of testing their software with the concept of a unit test. Many people in TDD think they’re running unit tests but in all actuality they’re performing basic integration tests. While most programmers test the functionality of their application using the user interface, this makes it very difficult to predict which of the elements caused the overall system failure.
Drawbacks of integration tests compared to automated unit tests
First, we must ask ourselves what it is exactly that we’re hoping to achieve with our real world unit tests. If you can’t use the same results that you used previously, be it a week, a month, or a year, then you have no way of knowing whether or not you’ve broken a feature you recently created. The code changes quite frequently over the lifespan of an application, so if you aren’t keeping track and testing regularly the previous working features after changing your code you may incidentally break it without knowing. This process is what Roy refers to in his book as “accidental bugging” and it seems to occur more and more often near the end of a software project once the developer is under pressure trying to fix all of the existing bugs in the code.
The focus on TDD
Test-driven development is very different works differently from traditional development in that it begins by first writing a test that fails. Then you move on to creating the production code, once you see the test pass you can continue on to either refactor your code or to create another failing test.
This is essential in unit testing because it helps programmers create high quality code, quality tests, and better designs for the code. In order to implement TDD techniques there’s three things you must do. First, write a failing test to prove code or functionality is missing from the end product. Since the test is written under the assumption the production code is already working, the test failing means there’s a bug in the production code. Then, you must make the test pass by writing the production code that meets those precise expectations of your past test. Finally, you refactor your code. Once the test has passed, you’re free to move on to the next unit test or refactor your code to make it more readable, to remove code duplication, etc.
When you perform your unit tests like the true art that it really is unit testing can be the difference between a failed project and a truly successful one, a maintainable code base and a code base that no one dares to touch and finishing your project by the deadline. The art of unit testing is written for .NET developers and it also discusses the most advanced test patterns and organizations, working with legacy and untestable code and frameworks like Typemock Isolator to simplify and make these tests possible.