A typical question those adopting TDD ask is: How much testing is enough? Or, put another way, does everything really need to be tested? How do you decide what to test and what not to test?
It’s an interesting question, but I prefer to address it this way: everything will be tested. The real question is, by whom? Will it be you, or someone else? Continue reading “How Much Testing is Enough?”
In TDD, the test suite can serve as a tool for quantitatively analyzing the qualities present (or absent) in the production code.
One example: A test will need to access the production entity that it is testing, obviously. However, sometimes a test needs to access another entity or entities as well, even though they are not currently under test. We sometimes refer to these collectively as a “fixture” for the test.
Continue reading “TDD and Coupling”
Tests pay you back for your effort:
- When you are writing them. They help you to understand the problem you are attempting to solve, they reveal gaps in your knowledge, and lead you to useful questions.
- When they fail. They inform you of a defect, and if written well, specifically where that defect is.
- When they pass. When you are enhancing or refactoring the system, tests passing confirms that you are only making the changes you intend to make.
- When you read them later. Tests capture knowledge that might otherwise be lost. And their accuracy can be instantly confirmed at any time in the future, by running them.
TDD does not cause extra work. It is just the opposite; it is one effort that provides value in multiple ways.
A test reacts to everything currently in scope that it does not control. Ideally, that should be only one thing. Everything else in scope must be controlled by the test, or it may react to the wrong thing and give misleading results.
For example, if a production entity uses a service call as part of its implementation, and the service being called is not what the test is testing, then that call must be controlled by the test because it is in scope.
This is a major reason to use a mock object.
Automated tests pass by default. A red test turning green proves everything.
The red test proves the validity of the test (that it can fail). Tests that cannot fail indicates an error in the way they are written.
The green test proves the code is accurate to the test. The code is written to pass the test, and so we know that it will forever be covered by the test going forward.
The transition from red to green proves that the test and the code are connected to each other. This is because we make failing test pass not by changing the test, but by changing the code.
TDD creates, therefore, meaningful test coverage. Nothing else can ensure this.
Test-first yields analysis, it helps us determine what is clear, what is unclear or missing, and ferrets out misunderstandings. Unit tests are unforgiving, they don’t let you get away with anything.
But Test-Driven Development also creates better design. Bad design is hard to test, and so moving tests into a primary position reveals the pain of a bad design very early, before much commitment has been made to it.
Write your tests first, but learn how to listen to what they tell you about your product design.
Design patterns are often described as “solutions to recurring problems within a context.”But the real power of patterns is to see the forces that each pattern resolves. They should be used as a way to help analyze what’s needed to create a quality design. That is the goal.
Given a situation where, say, the Strategy Pattern was not quite present but its concepts could be used, no one who understood patterns would criticize the solution by saying ,“Well, that’s not a Strategy Pattern!” So why do we hear these sorts of critiques in the process world? Let’s think about it. Continue reading “How Design Patterns Give Insights Into Process Patterns”
TDD is the first leg of emergent design or what could be called Agile Design. Design patterns are the second. They’re often described as “solutions to recurring problems in a context.” In this way they can be thought of as recipes that have been learned. But patterns open the door to much more; they are examples of ways to think. Patterns hide varying behavior, structure or which objects to use. Continue reading “Design Patterns: The Second Leg of Emergent Design”
I am heartened by the surge in TDD training. To me, TDD is the second most important thing for devs to learn. ATDD is the first.
TDD is not just the automation of unit testing. It’s also intended to improve design and sustainability.
TDD’s formulation of tests, prior to code, drives design. High quality code is easy to test. The reverse is also true. Code that is easy to test is higher quality than code that isn’t. I labeled this quality, “testability,” in my book Design Patterns Explained. Test-First is a process where deciding on your tests before writing your code improves your design. Continue reading “Test-Driven Development (TDD): The First Leg of Emergent Design”
With a name like TEST-driven development you’d expect TDD is mostly about testing. Especially when the end result is tests. In our book Design Patterns Explained we discussed how testability (how easily code can be tested) is an intrinsic property of software and is highly correlated with good design. This is why the 1st mantra of design patterns is to design to the behavior of the objects being written. These behaviors being described as tests.
One of the characteristics of good design is that it is modifiable with less effort than poor design. So testing first give us both better design of the code & increase its sustainability-enabling emergence. This is the big difference between test-FIRST and unit testing.
But we now have the added burden of the tests which often add to maintenance costs. The cause of this is insufficient focus on the quality of the tests. An ideal test will validate only one behavior. The intent is to decouple the tests so that when one behavior changes only one test needs to change. This requires attending to the coupling of tests as future enhancements are made. Coupling of tests inform coupling in design.