liveBook · Manning

Brittle test

As explained in Unit Testing Principles, Practices, and Patterns

Test fragility is the tendency of a test to fail when implementation changes without changing the tested behavior.

A brittle test runs quickly and may catch regressions, but fails when implementation changes without changing observable behavior. Its false positives expose coupling to the system under test’s internal details: it verifies how the result is produced rather than what the system does. section 4.4 section 5.2

Reduce brittleness by applying these rules:

  • Assert observable behavior instead of private methods, internal state, call sequences, or exact implementation artifacts. section 5.2 section 11.1
  • Use mocks for unmanaged dependencies whose interactions are observable externally; mocking other dependencies can produce brittle tests. section 9.0
  • Treat difficult testing of a complex private method as evidence of dead code or a missing abstraction, not as a reason to expose the method. section 11.1

Exact SQL versus observable behavior

A test that asserts `SELECT * FROM dbo.[User] WHERE UserID = 5` turns red when equivalent SQL changes whitespace, qualification, selected columns, or parameterization. It therefore protects against SQL-generation regressions while resisting legitimate refactoring poorly. section 4.4

Listing 4.6. Test verifying which SQL statement is executed
public class UserRepository
{
    public User GetById(int id)
    {
        /* ... */
    }

    public string LastExecutedSqlStatement { get; set; }
}

[Fact]
public void GetById_executes_correct_SQL_code()
{
    var sut = new UserRepository();

    User user = sut.GetById(5);

    Assert.Equal(
        "SELECT * FROM dbo.[User] WHERE UserID = 5",
        sut.LastExecutedSqlStatement);
}

Inspect the repository test that verifies the exact SQL statement executed, the canonical brittle-test example. section 4.4

How Unit Testing Principles, Practices, and Patterns covers it

How deep it goes
Explains false positives, implementation-detail coupling, mock usage, and private-method refactoring, but stops short of exhaustive mocking techniques.
Examples
Uses exact SQL assertions, exposed normalization methods, mocked dependencies, and complex private pricing logic as fragility examples.
What it assumes
Assumes familiarity with unit tests and introduces the distinction between observable behavior and implementation details.
What you can do after
Diagnose false positives and refactor tests toward observable behavior without exposing private implementation details.
How it connects
Connects brittle tests with observable behavior, implementation details, mocks, resistance to refactoring, and unit testing.

Also explained in

Compare how 3 books explain brittle test →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Unit Testing Principles, Practices, and Patterns. The section links point to the parts of the book it draws on.