I wrote Beyond Legacy Code to talk about the value of technical practices in software development. One of the most valuable technical practices for me has been test-first development and I really wanted to discuss it in ways that I hadn’t seen it discussed before that I found to be productive. Having exposed thousands of professional software developers to test-first software development, and Extreme Programming practice, I’ve learned firsthand how people respond to these ideas.
I noticed that often people’s first impression of test-driven development is as some form of testing and so they think about what can go wrong in a system as they write their tests. But this is the wrong way to do test-first development. TDD is not a form of testing but rather a form of specifying behavior before you build it. We call it a test in test-first development but really it’s an assertion of behavior, it’s a specification for a feature in the system, and when we think of it that way it makes a lot of sense to do it first before we actually implement that behavior.
When we start synchronizing the idea of the test and the behavior as one and the same we start to derive many benefits. A good well-written unit test articulates a behavior in the system. It not only specifies the behavior the way our requirements or specification document would but it also is guaranteed to be up to date because you can run it at any time and prove that it still passes. This gives us not only requirements traceability but also requirements verifiability in our system. That’s pretty good.
I know that as a developer it feels strange at first to write the test for a behavior before you implement the behavior but that’s just because we’ve all been taught to do things backward. When we think about it, it makes most sense not to just randomly dive into some part of the implementation and build out from there, it makes more sense to start by defining the behavior that we want to create and then defining it. This is exactly what we do in test-first software development, we write a test for the behavior that we want to create and then we implement the behavior by making the test pass. When we’re doing test-first development we say that no code is added to the system unless it is to make a failing test pass. When we follow that rule we find that we generally get 100% code coverage and our code coverage is not only high, it’s also meaningful because we’re asserting against behaviors.
TDD or test first-development is about writing unit tests for small pieces of behavior in a system whereas acceptance test-driven development or ATDD is about creating a test for a high-level behavior or feature in a system. Conceptually, TDD and ATDD are the same things except that they are at a different level of granularity.
In theory, TDD and ATDD are the same, and in practice they are different. We tend to use different tools with each and for different purposes. Because ATDD is at a high level we use it as a communication tool to define acceptance criteria with our stakeholders so we know when we’re done implementing a feature.
TDD (and I also use the term test-first development), on the other hand, is a developer practice used to define, build-out, and verify software as it is being created.
Still, ATDD and TDD have many things in common and many common benefits. The following seven blog posts are inspired by a section in my book, Beyond Legacy Code, called seven strategies for great acceptance tests. Enjoy these next seven blog posts.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Measuring Software Development.
Previous Post: « Keep Code Testable
Next Post: Get Clear on the Benefits of What You are Building »