TDD tests need to be run frequently. As an agile process, TDD needs to be responsive and flexible. Part of this is the ability to keep very short the feedback loop between tests and production.
To run tests frequently without excessive cost requires that they must be executed quickly. Here are some things that help keep tests fast. Continue reading “Keeping Tests Fast”
In TDD, we want to run the tests frequently. When we do so, it shortens the pulse of our work, increasing velocity. Also, when a test unexpectedly fails, we know that it must be something we just did that produced this result. It becomes very easy to find the error.
This means that we must be able to run tests frequently which in turn means that tests: Continue reading “Make Tests Repeatable and Independent”
It is important that the system behaviors we create as developers are both accurate and precise. These are not the same. One can be:
- Accurate, but not precise, such as “Pi is a little over three.”
- Precise, but not accurate, such as “Pi is 5.393858303895.”
They are not the same, but they are related. The level of precision required tells you how far to go in determining accuracy.
Here is an example. Continue reading “TDD and Accuracy vs. Precision”
Ideally in TDD, no more than one test is ever failing at any given point in time. This test represents the work that is about to be done but hasn’t yet. Also, this test should not spend a long time in the red. We want the suite to get back to “all green” as quickly as possible.
Here are some reasons for this: Continue reading “TDD: Keeping Tests Green”
TDD is a powerful way to develop new code. However, most organizations have significant existing code that was not developed this way. This “legacy code” is often difficult to test because it was not designed to be testable in the first place.
In his excellent book, Working Effectively with Legacy Code, Michael Feathers outlines techniques for dealing with this kind of code, with an eye toward making it more testable. This book is an essential resource for anyone that has significant legacy code. Continue reading “TDD and Legacy Code”
Refactoring is defined by Martin Fowler as “improving the design of existing code.” Refactoring stipulates two things: that behavior does not change, and that the design has been improved. While developers have been “cleaning up” their code from the very early days, Fowler made this a discipline that developers can collaborate within. He defined a shared way to do it. Continue reading “The Value of Refactoring Skills”
Abstract classes in languages like Java or C# serve two purposes: they create polymorphism in design, and they are a convenient place to put behavior that is common to all derived classes, avoiding redundancy.
But if all behavior in TDD needs to be tested, and if instance behavior implemented in abstract classes cannot be tested (because they cannot be instantiated), then how can we adhere to our process? Continue reading “TDD: Testing Adapters for Abstract Classes”
TDD depends on a strong connection between the automation of the test suite and the system itself. The suite should record the specification that is implemented in the system, and the connection allows this to be confirmed at any point.
The problem is automated tests pass by default. So, if errors creep into the test code that breaks the connection to the system (the tests are not really doing anything) they would still pass under most circumstances. Continue reading “Sustainable TDD: Part 3”
Project managers have to balance resources. Spending them on one thing means not spending them on another. So, when the team adopts TDD, it is understandable that attention is paid to the level of resource needed to sustain it over time.
It’s not uncommon for project managers to notice, as the project grows, that the creation of tests and their maintenance seems to be an increasingly large drain on resources. Team leads may note that the suite of tests is actually larger than the production code base, sometimes far, far larger. Continue reading “Sustainable TDD: Part 2”
TDD is typically part of an agile process. This means that we embrace change, that new requirements flow into the team’s work either on a time-boxed pulse, or through some kind of pull system (like Kanban). In TDD, a new requirement always starts out as a new, failing test or “specification.” We write the test to express the requirement before it has been fulfilled.
Then, work is done in the system to make this new test pass. Over time, however, developers begin to experience the syndrome where making the new test pass makes older tests fail. Those tests must be maintained (you cannot leave tests “in the red”) which burdens the team. This problem tends to get worse over time. Continue reading “Sustainable TDD: Part 1”