Python Testing Tip #3 / March 11, 2024

Testing behavior, not implementation details – part 1

This article explains why "test behavior, not implementation details" matters in software testing, using practical examples.

What is Software Behavior?

Software behavior refers to what the application does and how it responds to different inputs. Examples include:

  • Creating and listing tasks
  • Handling API failures by defaulting to alternatives
  • Redirecting unauthenticated users
  • Sending welcome emails upon signup
  • Managing email bounces

What Are Implementation Details?

Implementation details are the chosen methods for achieving desired behaviors. Multiple valid approaches may exist, but changing them shouldn't alter the observable behavior.

Key Differences

When testing behavior:

  • Tests use only public methods of objects
  • Tests remain unchanged when implementation changes
  • No database-specific code (like SQL) appears in tests
  • Better readability and maintainability
  • Improved refactoring resistance

When testing implementation details:

  • Tests are tightly coupled to specific technologies
  • Changes to database structure, column names, or storage methods require test modifications
  • Tests become brittle and less protective against regression
  • Multiple tests may test single methods instead of complete behaviors

Practical Example

The article contrasts testing a task storage system with SQLite versus an in-memory store. Both implementations can use identical tests if focused on behavior: "When I add a task, I want to see it in the list."

Conclusion

A diagnostic question: "Can I replace my implementation with a different one without touching the tests?" Affirmative answers indicate behavior-focused testing, while negative responses suggest implementation-detail testing.

Share this tip

Get Python Testing Tips in Your Inbox

Practical Python testing advice delivered to your inbox.