Optivem Journal

Optivem Journal

Test Driven Development

TDD: High Coupling vs. Low Coupling Tests

When writing tests, it’s not enough to “just have tests.”

Valentina Jemuović's avatar
Valentina Jemuović
Nov 14, 2025
∙ Paid

🚫 High coupling – Tests coupled to Structure ➔ Fragile Tests

Do NOT write tests as specifications of your implementation.

When your tests know too much about the system’s internals (specific classes, methods, or dependencies), the tests become tightly coupled to the implementation, i.e. the internal structure.

If you change an implementation class, the test will break. This kind of testing leads to fragile tests.

🔍 Example symptoms:

  • Tests instantiate internal classes directly

  • Tests depend on method names or call chains

  • Small refactorings cause test failures even when behavior hasn’t changed

💥 The result:

  • Refactoring becomes risky and slow

  • Developers fear touching the code

  • Tests no longer describe behavior — they describe implementation details

✅ Low Coupling – Tests coupled to Behavior ➔ Stable Tests

DO write tests as requirements of the system.

Tests should communicate with the module’s public API and test the module’s external behavior. A module consists of a group of classes, where one class acts as the public class (exposes the module’s public API, it’s the entry point to the module) and the other classes are internal classes (they are implementation details of the module).

When our tests don’t know about implementation (treating it as a black box), we can change the internal implementation and we’re not going to break the tests.

We can do as much refactoring as we want, and the tests will not break.

✅ Characteristics:

  • Tests verify the module’s behavior, not its internal implementation.

  • Internal classes can change freely without breaking tests.

  • You can refactor safely and move fast.

💡 Example:

  • Your tests call OrderService.placeOrder() instead of directly testing the underlying repository, entity, or validation class.

  • If you refactor OrderService or your validation class, the tests still pass — because behavior hasn’t changed.

Real-life Example: Ordering System

This post is for paid subscribers

Already a paid subscriber? Sign in
© 2025 Valentina Jemuović, Optivem
Privacy ∙ Terms ∙ Collection notice
Start your SubstackGet the app
Substack is the home for great culture