A Gentle Introduction to Test Driven Development (TDD)

TDD is all the rage and the best thing since sliced bread. TDD is a terrible abomination that should die a quick but very painful death. TDD is great. TDD is terrible. If you look for information on TDD, you can get all of these opinions and everything in between. This is actually very encouraging. Because there are so many strong, heartfelt opinions and some of those opinions are so polarizing, it means the topic is a good one and you should learn about it and form your own opinion and take a stance.

What is TDD?

TDD, or test driven development, is the practice of writing a test before writing code and then writing only enough code to satisfy the test. Then, refactoring that code so that the code is as good as you can make it while still satisfying the test. This is, of course, the 10,000-foot view. When you get closer to ground level, though, you can see more details. For example, the test should be complete. It should be testing what is really important. Only when you are completely happy with the test should you start writing code that passes the test. This process, this cycle, is very important. If you leave any of those steps out or if you don’t approach the steps with wholesome good and understanding, you are not satisfying the requirements.

If you have come into a project that actively used unit tests but not TDD, you have no doubt seen, first-hand, useless tests. Tests that are created to make the developer feel good about the time they are taking to create them or tests that are there to increase code coverage but tests that are, nonetheless, completely worthless. Tests that measure the most mundane, unimportant things. Tests should give value beyond the success of the test. Tests should be measuring the quality and accuracy of the code.

TDD does have a real effect on the architecture of your program. If you are really testing features, there are several ways that feature could be designed and there are many ways that it cannot or should not be designed.

Imagine this scenario: You need to retrieve data from a logic class that will first gather that data from a repository class. It is likely that you will have to design the method in your logic class to be loosely coupled with a repository interface and not a concrete repository class. It is also likely that you will need to either inject that interface class through dependency injection or provide it in another way. It just so happens that both of those practices should be considered best practices. They make your code more flexible and resilient. And, if you are following the ‘only enough code to satisfy the test’ tenet of TDD, you likely don’t have a lot of superfluous code in your method that will have to be refactored. In the end, you will have a cleaner code base and a code base that you can feel more confident about because of the suite of tests you have designed.

I am not an advocate of TDD. I find it just too much on smaller projects and, in larger projects, it takes a mighty amount of discipline to keep in top shape. However, when I do practice it, I am generally happy with the results. The architecture and code are clean and more resilient. The problem is the discipline. In my personal projects, I just don’t always have the energy to practice TDD. Call it laziness if you would like.

Advocates of TDD would likely tell you that TDD is always the answer which is opinion, not fact. Sometimes, TDD is completely worth it and sometimes it just isn’t. Penicillin, which has saved the lives of more people in history than other medication (approximately 200 million), isn’t always the answer either and you should be wary when told that TDD is always the answer.

Pros

There are plenty of pros but the main arguments are listed below.

  • The architecture of your applications evolves slowly and methodically in a very controlled manner.
  • Components of your application will be (usually) loosely coupled because they are being tested.
  • The code is much easier to refactor because you will know if you have broken anything when tests fail.
  • Unit tests can often be better than written documentation because they are another form of documentation that developers should find easy to understand.

Cons

Again, these are just the main arguments but there are cons aplenty, also.

  • Tests have to be maintained and there is an expense in doing so.
  • Writing tests is not the same thing as writing good tests.
  • TDD requires more up-front work but the argument can be made that it will save time and effort in the long run.
  • Nearly impossible to do for legacy code. This makes it more difficult for teams to do because doing TDD on one project and not on another because it makes for a more jumbled experience.

The Tools

There are two main tools you will need in order to practice TDD effectively. First, a unit testing framework. Unit testing frameworks allow you to create the tests that measure your code. These frameworks exist for just about any language available and many languages have several unit testing libraries available.

  • Nunit (.NET)
  • JUnit (Java)
  • PHPUnit (PHP)
  • PyUnit (Python)

The second tool you will need is a mocking framework. Each mocking framework will come with their own rules of use but, in general, mocking frameworks allow you to build mocked-up endpoints to classes and interfaces in your code so that you eliminate dependencies on external resources. For example, a repository class can be mocked to eliminate the dependency on a database or folder structure. Again, there are mocking frameworks available for just about every possible programming language and many languages will have more than one. Here is a list to match the frameworks above.

  • Moq (.NET)
  • JMockIt (Java)
  • Phake (PHP)
  • Mox (Python)

Conclusion

As you can see, there is not an easy answer for whether or not you should be doing TDD. It has its benefits and drawbacks. In the end, you have to make the best decision for your specific project and your specific team. Regardless of whether you do practice TDD or not, the more information you have, the better off you will be in the long run. In a later post, I will show the entire TDD process of a small application being developed from start to finish. Hopefully, this will make it easier for you to form your own opinions about TDD and whether or not it is for you.

Leave a Reply

Your email address will not be published.