Dev Diary #1: TDD Is Easy, When You Forget About The Code

Written by joebrady | Published 2024/08/21
Tech Story Tags: javascript | tdd | testing | integration-testing | test-driven-development | typescript | dev-diary | what-is-tdd

TLDRFind test-driven development hard? Make it easier by forgetting about the code and starting with comments to write a simple plan.via the TL;DR App

As a big advocate of Test-Driven Development (TDD), I have spent a good amount of time wondering why 95% of my conversations about TDD with other engineers go something like this:

ā€œYes, TDD is clearly the right way to build software. But I donā€™t actually do it.ā€

At this point, the usual reasons and explanations are laid out:

ā€œItā€™s hard to know what tests to write until I have written the code.ā€

ā€œHow can I know how the tests should work if I donā€™t know how the code works?ā€

It is true that if you are testing something that uses completely unfamiliar technology, you probably donā€™t know yet how to go about testing it. Most of the time, though, the technology is perfectly familiar. Itā€™s not the tools that are unfamiliar and scary - itā€™s the product that you are trying to build.

Enter my āœØOne Simple Trickā„¢āœØā€¦

Forget about the code completely (for now). All of it. Donā€™t think about the implementation, and donā€™t think about the test code either.

Instead, just write a plan for how the product should work. Hereā€™s how I do it:

Step 1

Start by writing simple comments in human language. Write as many as you can think of, with one per requirement, acceptance criteria, scenario, edge case, or error. Hereā€™s an example:

// animals.test.ts
// Plan for new API endpoint: GET /animals

// returns a list of animals with the ID and name

// paginated 10 at a time by default

// can change the pagination size

// optionally filters by species type (in the query params)

// returns a 403 error if not authenticated

Of course, the code has to happen at some point. But by starting with comments like this, it removes all of the psychological resistance to the idea of writing tests, allowing you to focus on what youā€™re trying to build.

Step 2

Write the actual tests one by one by converting each comment into an assertion.

// animals.test.ts

import { request } from "supertest";
import { app } from "./app";

it('returns a list of animals with the ID and name', async () => {
  const result = await request(app).get('/animals');
  
  result.forEach(animal => {
    expect(animal).toEqual({
      id: expect.any(String),
      name: expect.any(String),
    });
  });
})

// paginated 10 at a time by default

// can change the pagination size

// optionally filters by species type (in the query params)

// returns a 403 error if not authenticated

It is worth noting that this technique is best paired with the philosophy of Write Tests. Not Too Many. Mostly Integration. While the ā€˜comments-firstā€™ approach can be applied to unit tests, it is much easier to start with higher-level, more product-focused integration tests.

Step 3

Write the bare minimum application code to make the first test pass.

For example, to make this first test pass, you could return this hardcoded array from the API endpoint:

// animals.ts

res.send([{ id: "foo", name: "bar"}]);

Step 4

Clearly, this isnā€™t enough. The urge to immediately write more code is strong.

This critical moment is the final hurdle to overcome, and it is the hardest. Resist the urge! Stop, take a deep breath, and look back at your commented plan. Is there anything on that list that will force you to change the code to fix the glaring issue that youā€™ve seen?

If yes, great! Keep going, it will be fixed soon.

If not, you have two options:

  1. Improve your current test to have more specific checks
  2. Add another comment to your plan for the missing requirement

Step 5

Repeat the process. Write the next test, check that it fails, and then write the minimum code to make it pass.

Thatā€™s it.

Congratulations, you just TDDā€™ed! It will be worth it, I promise.

Thank you for reading. This is the first of my new series, Dev Diaries, where I will be writing about something Iā€™ve done, something Iā€™ve learned, or something that Iā€™ve found interesting that day.


Written by joebrady | London-based Staff Software Engineer. Built things for Vogue, GOV.UK, Marks & Spencer, Lloyds Bank, & New York startups.
Published by HackerNoon on 2024/08/21