Craft Better Software

Craft Better Software

Share this post

Craft Better Software
Craft Better Software
TDD: 5 test smells - 5 solutions

TDD: 5 test smells - 5 solutions

5 practical tips to improve the quality of your tests

Daniel Moka's avatar
Daniel Moka
May 28, 2024
69
Error

Share this post

Craft Better Software
Craft Better Software
TDD: 5 test smells - 5 solutions
9
5
Error
Share

50% OFF - The Complete TDD course

Are you ready to master clean code, testing and Test-Driven Development (TDD)?

I recently launched a complete TDD course containing everything you need to craft high-quality software.

Now there is a 50% OFF for the course

Get instant access by clicking here.

Get Instant Access

Motivation

You can’t have clean code without clean tests. Treat your tests as first-class citizens. Writing clean tests is as important as writing clean production code.

When I help teams to improve their testing practices, I always see the same 5 test smells. Here’s what they are, how to detect them, and how you can fix them:

1. Fragile tests

❌ Problem

Your tests fail to compile when you change the production code.

🔃 Cause

Your tests are coupled to low-level implementation details such as internal functions or classes.

As you see in this example below, the test is coupled to implementation details like FindById(..) and Store(..) methods.

✅ Solution

Don't couple your tests to implementation details or code structure. Instead, couple them to the behaviors of the public APIs.

The following test uses fake to verify state changes without being coupled to the internal functions:

2. Eager tests

❌ Problem

The test is hard to understand as it verifies too much functionality in a single test method.

🔃 Cause

Having multiple Act and Assert parts within a test.

The following test is an Eager Test because it covers multiple behaviors: bank account creation, deposit, invalid withdrawal, and successful withdrawal.

✅ Solution

You can fix the Eager Test smell by splitting up the test into multiple test cases. Each test should verify a single condition:

3. Mistery Guest

❌ Problem

The reader must look outside the test to understand the behavior being verified.

🔃 Cause

Some global context is used to initialize data for reusing objects and avoiding duplication.

In the following test, we don’t have any info about the User as it is initialized outside the test context:

✅ Solution

Include everything needed in the test to understand the tested behavior. The Don't Repeat Yourself principle is less important in test code. Prefer readability over removing duplication:

4. Test with irrelevant data

❌ Problem

It's hard to tell which data affects the test result.

🔃 Cause

There is too much irrelevant information in the test case.

✅ Solution

Don't pollute your tests with irrelevant test data! Irrelevant data increases noise and decreases readability. A test should read like a story with only the essential information.

There are two great ways to hide irrelevant data:

  • abstract irrelevant information into a method

  • use the builder pattern

5. Test with logic

❌ Problem

Tests are too complex to understand and prone to bugs.

🔃 Cause

You use logic in tests such as if-else statements, loops, or switch cases.

✅ Solution

Avoid any logic in your test code! Once you feel the need for these, it's a smell that you test more than one thing. You can get rid of test logic by splitting up your tests into multiple test cases.

Another option is to use parameterized tests to declare your test cases and to avoid duplication:

Conclusion

Writing quality tests is a skill worth its weight in gold. To master testing, I made a Test-Driven Development course, including:

  • Other test patterns and anti-patterns

  • How to write clean tests

  • The 5 different test doubles

  • The two schools of TDD

  • The power of mutation testing

  • 3 real-world projects in C#, TypeScript and Rust, built with TDD

Join 200+ developers to master TDD by clicking here.

Get Instant Access

Pushpender Singh's avatar
nima's avatar
Ravi Kumar's avatar
Alexandre Zajac's avatar
Lasha Dolenjashvili's avatar
69 Likes∙
5 Restacks
69
Error

Share this post

Craft Better Software
Craft Better Software
TDD: 5 test smells - 5 solutions
9
5
Error
Share

Discussion about this post

User's avatar
alpsavas's avatar
alpsavas
May 29, 2024

It not only points out the wrong but also shows the right approach in each example. Very well structured newsletter.

I only do not understand fully the 4th example, though. Should I change the existing or add a new implementation to construct an object with less parameters just for test clarity, in this example?

Expand full comment
Like (1)
Reply
Share
1 reply by Daniel Moka
Raul Junco's avatar
Raul Junco
May 29, 2024

Well explained, @danielmoka. I loved the examples!

Expand full comment
Like (1)
Reply
Share
7 more comments...
Clean Code: 7 tips to write clean functions
You know your code is clean when every function does just what you expect
Jul 8, 2024 • 
Daniel Moka
382

Share this post

Craft Better Software
Craft Better Software
Clean Code: 7 tips to write clean functions
15
Stop Using NULL. It's a Bad Practice
How to prevent the million dollars mistake
Jan 27 • 
Daniel Moka
115

Share this post

Craft Better Software
Craft Better Software
Stop Using NULL. It's a Bad Practice
4
Refactor like a PRO
The art of continuous, safe and aggressive refactoring
Apr 12, 2024 • 
Daniel Moka
96

Share this post

Craft Better Software
Craft Better Software
Refactor like a PRO
5

Ready for more?

Error
© 2025 Daniel Moka
Privacy ∙ Terms ∙ Collection notice
Start writingGet the app
Substack is the home for great culture

Share

ErrorError

Create your profile

User's avatar

Only paid subscribers can comment on this post

Already a paid subscriber? Sign in

Check your email

For your security, we need to re-authenticate you.

Click the link we sent to , or click here to sign in.

User's avatar

Gina Acosta, a subscriber of Craft Better Software, shared this with you.