One pair programming configuration I like is called ping-pong pairing.
In ping-pong pairing, the driver writes a test for a behavior then asks the navigator to implement the behavior and make the test pass. Once completed, the keyboard is passed from driver to navigator and the new driver writes the next test for the new navigator to implement.
This back-and-forth between test and code, driver and navigator, can offer rich feedback when building a system. It also supports developers in doing test-first development.
One of the challenges with ping-pong pairing is making the time to refactor both code and tests. It’s easy to get on a forward momentum where features are being implemented, but we also have to take the time to step back and make sure our code is clean so it’s straightforward to maintain and work with in the future. This also applies to our tests.
I find that when doing TDD, I spend a fair amount of time refactoring my tests. Sometimes, I spend more time refactoring my tests than refactoring my code, but this is natural. Exercising a feature can be complex, so testing can be complex, too — but it’s well worth it to make tests straightforward and easy to read.
The two things I typically do to make my tests more readable are factor common set up behaviors into a common setup method and, for any additional functionality that is not shared among all tests, write helper methods that my test can call.
You might have heard me rant in the past about how helper methods have no place in the domain model. They’re orphaned behaviors because the developer who wrote them didn’t take the time to discover what object should actually possess those behaviors and instead they made a helper object hold those behaviors. Doing this distorts the domain model. It means that objects in our domain model are not being called out correctly and therefore the domain model is distorted and difficult to understand. So, it’s true: I am against helper methods in production code.
However, helper methods do have a place in test code. Test code is, after all, different than production code. It has a different purpose. It’s intended to exercise production code, so it makes complete sense for tests to have helper methods.
Tests are, after all, code, and they’re important code because they exercise a production system. We should write our tests with every bit as much care as we use to write production code.
Ping-pong pairing helps us keep an emphasis on both test and production code and can support pairs in doing TDD well.