advanced · 30 minute study
A deterministic test controls the sources of uncertainty
Make a test meaningful by controlling time and external I/O while still verifying the behavior that users depend on.
Useful preparation · 1 prerequisite
Use this as a map, not a lock. If these ideas are familiar, continue.
- Decode data and release resources at explicit boundaries — Build import/export utilities without treating a successfully deserialized file as automatically valid domain data.
First, build a mental model
A test is an experiment: arrange controlled inputs, perform behavior and compare the observable result with a requirement. Dependency injection makes a source of uncertainty explicit so a focused test can replace it.
- A unit test isolates a rule; an integration test checks real collaborators and boundaries. Both are needed for different failure modes.
- Inject a clock rather than reading current time inside every rule; boundary cases then become reproducible.
- A test double can control a dependency, but cannot prove the real implementation's database or network behavior.
- Use the project's configured test framework and `dotnet test`; a green command matters only if the intended tests actually ran and the asserted contract is useful.
static bool IsExpired(DateTimeOffset expiresAt, IClock clock)
=> clock.UtcNow >= expiresAt;
var boundary = DateTimeOffset.Parse("2026-01-01T00:00:00Z");
IClock clock = new FixedClock(boundary);
Console.WriteLine(IsExpired(boundary, clock));
interface IClock { DateTimeOffset UtcNow { get; } }
sealed class FixedClock : IClock
{
public DateTimeOffset UtcNow { get; }
public FixedClock(DateTimeOffset now) { UtcNow = now; }
}
// In your test framework, assert before / exactly-at / after expiry.
// This page does not run dotnet test or claim a test passed.- Requirement
The example contract says equality with the expiry instant counts as expired.
- Control
FixedClock supplies an exact instant, so wall-clock timing cannot make the result flaky.
- Observe
The method returns true at the boundary. Neighboring cases should be tested separately.
Production thinking
Take this beyond the example.
Keep cheap deterministic rule tests close to development and run meaningful integration checks at external boundaries. Match DI lifetimes to ownership; do not capture request-scoped state inside a long-lived singleton.
Sources and further reading
Your evidence
unseen is a local learning signal, not a credential or proof of production competence.
Explain the mental model, then explicitly acknowledge it. Opening a page is not evidence.
Supported retries can complete this lesson. Independent evidence and delayed review determine the skill stage.
Next lesson · .NET applications need an explicit authority and deployment boundary →