Douglas ’ Blog

TDD is overrated

~ Feb 19, 2024 ~

Software testing is a vital practice in software development. Without it, changing or fixing software becomes a nightmare.

But there are some concepts that I don’t think are useful in a day to day practice.

In my first post, I wrote that you should ignore test doubles and TDD. I will expand on why. Also, I will take the opportunity to talk about other concepts related to tests.

Ignore Test Doubles

First, what are test doubles?

Test Double is a generic term for any case where you replace a production object for testing purposes.

There are five different types of test double. But in practice, you only need a stub, a fixed result, to make your test reliable. That way, the test won’t depend on the database, randomness, current time, network requests, etc.

Let’s go one by one.

Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.

This looks like it’s just a bad function signature design.

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an InMemoryTestDatabase is a good example).

A better approach is to do an integration test instead. Otherwise, you are just testing the InMemoryTestDatabase implementation.

Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.

I’m not sure why this would be useful. But from my perspective, this is also better as an integration test.

Mocks are pre-programmed with expectations which form a specification of the calls they are expected to receive. They can throw an exception if they receive a call they don’t expect and are checked during verification to ensure they got all the calls they were expecting.

Mocks are similar to Fakes but way worse since it has more code specific for the test. Just do an integration test already.

Ignore the test pyramid

What is the test pyramid?

The test pyramid is a way of thinking about how different kinds of automated tests should be used to create a balanced portfolio. Its essential point is that you should have many more low-level UnitTests than high level BroadStackTests running through a GUI.

My first gripe is that the separation of each layer is unclear. For example, how do you define what is a unit or integration?

Also, excessive unit tests take time, and if the code is not necessary anymore, the tests are no longer needed.

I generally disagree that E2E tests are expensive to write and execute. E2E tests should be generally fast, and you can also select which tests to run. Even unit tests could be slow if there are a lot of them. When the time comes, you optimize.

What is expensive is not having a good test suite.

My general advice is to focus on writing tests for large portions of the code, which will give a high amount of confidence. I will also leave this Reddit comment as advice.

Ignore 100% coverage

You can achieve 100% coverage. Sometimes, the tool might count some code that is not relevant. So, you can safely configure to ignore that. Also, probably higher test coverage has diminishing returns, so be careful not to be obsessed with 100% coverage.

Ignore “One assertion per test”

The book “xUnit Test Patterns: Refactoring Test Code” describes a test behavior smell: Assertion Roulette.

It is hard to tell which of several assertions within the same test method caused a test failure.

So, the solution is to write only one assert per test. This advice also appears in the Clean Code book.

I don’t know why they came up with this advice, but nowadays, the test tool can output the exact line of the failed assertion.

My advice: write as many asserts as you need, only if those are related to what you are testing.

Ignore F.I.R.S.T.

This acronym is from the Clean Code book, which can be summarized as follows:

Tests should run in parallel, be fast, deterministic, and cover all paths.

Ignore TDD

The benefits that some developers claim about TDD aren’t exclusive of TDD. Doing tests after has the same benefits. It’s just a matter of style. The only problem is not writing tests.

There are some scenarios where using TDD is not possible, especially if you are still figuring out what the code should be.


Always remember:

Software without tests is not maintainable.