// Asserts that a mock was called. Never runs the database translation.
[Fact]
public async Task Handler_ShouldCallRepository()
{
_repo.Setup(x => x.Get(id)).ReturnsAsync(row);
await _handler.Handle(command, ct);
_repo.Verify(x => x.Add(It.IsAny<Row>()));
}
Green mocks are not a specification
An agent uses tests as the fastest way to learn allowed behaviour. Names should describe the product. The host should be the real pipeline. Default Layered tests that mock the next layer score 0% on the persistence path that usually contains the bug.
// Names the business rule. Hits routing, mapping, EF, and the status union.
[Fact]
public async Task When_funds_are_insufficient_the_provider_is_not_called()
{
var body = await Post("/commands", amount: 9_999);
Assert.Equal(Status.Insufficient, body.Status);
Assert.Null(body.TransactionId);
}
Name the condition
Prefer When_account_is_unknown_operation_returns_NotFound over type-and-method names. An agent searching the test explorer should find the product rule, not the class that happens to own it.
Boot the real host
A web application factory with an isolated database file exercises JSON, routing, and the query provider. That is the documentation of “what HTTP does.”
Cover the outcomes
If a status exists on the closed set, a test should be able to produce it. Success, unknown account, invalid amount, unknown partner, decline, and limit exceeded are the minimum for this domain.
The translation bug pattern
A LINQ filter that looks correct in C# may not translate on the database you actually run. HTTP tests against that database fail loudly. Mocked repositories return a canned sum and stay green. Treat that as a correctness gap of 100% vs 0% on the path that matters — not as equivalent coverage numbers.
Cross-app tests
- Consumer-driven contracts against the owner’s real schema.
- One black-box operation test in the owning app remains the source of truth.
- No fake client inside a façade that returns Success for every input.
What this does to the pillars
- Token cost. A named test is cheaper than rereading production code to learn the rule.
- Developer involvement. Failures point at behaviour, not at a mock setup the reviewer cannot trust.
- Correct output. Default tests that exercise I/O catch the class of bugs mocks systematically miss.