Remember the Design!
The next morning we had a retrospective on our experience from the first day. John asked whether I had figured out what the problem was from the end of the previous day. I was hung up on test idea generation, so I was sure I must be missing an important test. He told me that by the end of the day he knew we were in trouble from a design perspective. Sure, we had lots of tests, but there was a "smell" in the code he wanted me to learn how to catch. Our tests were getting more complex, with a lot of setup required, and the code was becoming more awkward. In fact, we hadn’t realized it at first, but John pointed out that I hadn’t been driving (typing at the computer) at all for a couple of hours that afternoon. At this point, whenever we added new tests, he had to add them because the code had become complex and it was difficult for me to add tests.
We went over where I had gone wrong. I was only thinking about test idea generation, while John was simultaneously thinking of tests, improving the software design, and continuously improving the testability of the code. Because John was a good teacher, he had deliberately developed a "bad code smell" and tried to guide me into seeing it. But I was so focused on generating testing ideas that I missed it. John deliberately made the unit tests awkward and difficult to implement, but I simply trusted his design and took the complexity for granted as a technical issue that I didn’t understand. I didn’t realize that the fact that the tests were onerous and difficult to set up and code was a "bad test smell."
He explained that if we can add tests simply, it’s a sign of a good code design. Since the tests were awkward and I was dependent on the programmer to add them, I needed to be concerned. As a tester, part of my job when pairing in a TDD situation is to watch for bad test smells. Those bad smells in the tests are symptoms that something is wrong with the code. John pointed out that when it’s difficult to test, it’s time to improve the code. When testability is improved, one by-product is a better design.
Even though I didn’t have John’s architectural experience, he was confident that testers can learn to spot these smells in code. It doesn’t take a lot of programming skill to realize that some unit tests are awkward while others are simple and elegant—it just takes practice.
We continued our development, but I noticed that some parts of our pairing sessions went smoothly while others felt difficult. Later on, I talked with William Wake about how I struggled with some areas, as a tester pairing with a developer. He told me that there are two test activities in TDD:
- Generative tests are the first tests that are written, primarily about design. They’re "shallow sweep" tests that yield the initial design.
- Elaborative tests are deeper, more detailed tests that play out the design and variations.
In the generative phase, testing felt much more like programming and design, and wasn’t a natural fit for me as a tester. In this phase, test idea generation could frustrate development. Elaborative testing felt more natural. The sky was the limit for test ideas we could generate and try out, and test failures demonstrated weaknesses in the design that we could tighten up, or provide testing ideas for functional testing we would do later on.