Unit Tests That Add Value

Unit tests only deliver real value when they verify behaviour and business logic rather than implementation details. Trivial or fragile tests are dead weight. Valuable tests build confidence during refactoring, document intended behaviour, and cover failure cases.

Bernhard Trinnes
Bernhard Trinnes
Unit Tests That Add Value

Unit tests are a standard tool of professional software development. Yet they often end up as tedious formalities: tests that barely verify anything, break at every small change, or merely confirm the obvious. For unit tests to deliver real value, you need clarity about their purpose and benefit.

Common Problems with Unit Tests

  • Trivial tests: they only check getters/setters or mirror the implementation line by line. Value: zero.
  • Fragile tests: even minor refactorings cause failures, without any change in behaviour.
  • Missing focus: tests verify incidentals rather than the business-critical rules.
  • Unreadability: complex test logic that is harder to understand than the production code itself.

What Makes a Test Valuable?

A good unit test satisfies at least one of these conditions:

  • It covers business-relevant rules (e.g. price calculation, safety check).
  • It builds confidence in refactorings by testing behaviour rather than implementation.
  • It documents intended behaviour in a readable and traceable way.
  • It provides fast feedback when something goes wrong.

Principles for Adding Value

  1. Test behaviour, not implementation. Instead of assertEquals(42, obj.getValue()) just because getValue() happens to return 42, build a scenario that makes business sense.
  2. Keep tests independent. Every test must be able to run in isolation, without hidden dependencies.
  3. Use descriptive names. A test named shouldRejectInvalidPassword() is also documentation.
  4. Don't forget edge cases. Failure paths, boundary values and exceptions often reveal more than happy-path tests.
  5. Think about maintainability. Tests are code and need care. Clear structures and helper functions make them robust.

Example: Valuable vs. Trivial

Trivial:

TEST(UserTest, GetNameReturnsName) {
    User u("Alice");
    EXPECT_EQ("Alice", u.getName());
}

No real value — it only confirms that getName() returns what was set in the constructor.

Valuable:

TEST(PasswordTest, RejectsShortPasswords) {
    User u("Alice");
    EXPECT_THROW(u.setPassword("123"), std::invalid_argument);
}

This test verifies a business rule: passwords must meet minimum requirements.

Conclusion

Unit tests that add value focus on behaviour, rules and robustness. Their job is not to mirror the implementation but to build confidence and preserve knowledge. Poor tests are dead weight; good tests are investments in quality and maintainability.