2 min read

TDD: Act-First to Drive Design

TDD: Act-First to Drive Design

I know tests should drive the design, but I never really understood how to do it. And I don’t feel like asking so people don’t think I’m anti-TDD.

One of my students

Over the years being a tech lead, I saw this is a common challenge. And that having tests driving the design is difficult because we have to think differently.

I know a trick for that: you have to write the tests in a different way.

I’ll show you.

How a good test looks like

A good test follows Act, Arrange, Assert, the famous AAA format.

Arrange is where you set up the test. You create objects, data, configurations. Everything necessary for the test to run.

Act is where you execute the code to be tested.

Assert is where you check if the result is correct. You compare it with what you expected.

Example:

test('10H 10C 10S 10D 2H is a four of a kind', () => {
  // arrange
  var hand = new PokerHand('10H 10C 10S 10D 2H');

  // act
  const handName = hand.name();

  //assert
  expect(handName).toEqual('Four of a kind');
});

You read the test in the chronological order in which things happen: first arrange, then act and finally assert.

How to write tests

But that’s not the order you should write the test.

Kent Beck, the person who “rediscovered” TDD, recommends writing the test in reverse, beginning with the assert, followed by the act and then arrange.

Check it out:

When I test assert-first, I find it has a powerful simplifying effect. When you are writing a test, you are solving several problems at once, even if you no longer have to think about the implementation.

Where does the functionality belong? Is it a modification of an existing method, a new method on an existing class, an existing method name implemented in a new place, or a new class?

What should the names be called?

How are you going to check for the right answers?

What is the right answer?

What other tests does this test suggest?

Pea-sized brains like mine can’t possibly do a good job of solving all of these problems at once. The two problems from the list that can be easily separated from the rest are: “What is the right answer?” And “How am I going to check?

Kent Beck, on Test Driven Development: By Example (page 128, Assert First)

Kent argues that by writing the assert first, you’ll have the answers for these questions right away and then work backwards to answer the other ones.

I agree, but only if your main purpose for testing is making sure the result is correct.

Test Driven Development Design

When we’re designing, we’re creating how the object interacts with the world. When we’re designing, more important than the operation’s results, is the operation in itself: its name, its dependencies, parameters format and name, result type and so on.

What matters is not the answers to those questions, but to these ones:

Where does the functionality belong? Is it a modification of an existing method, a new method on an existing class, an existing method name implemented in a new place, or a new class?

What should the names be called?

And if this is the most important, the executed code should be the focus of the test. The result is secondary.

If you want to use tests to drive the design, test act-first.

Do it this way and see how your mind will flow from “test mode” to “design mode”.

(Header photo by Rod Long on Unsplash)

***