Reducer tests are most useful when they prove state transitions and effect cancellation without waiting on real time or infrastructure.
let clock = TestClock()
let store = TestStore(initialState: SearchFeature.State()) {
SearchFeature()
} withDependencies: {
$0.continuousClock = clock
$0.searchClient.results = { _ in [.fixture] }
}
Send the user action, assert immediate state, advance the clock through debounce, then receive the response action and assert final state.
Inject UUID generation and dates when they appear in behavior. A chat retry test should reuse the exact client turn ID; a workout timer should advance on the test clock.
Streaming dependencies can return an AsyncStream controlled by the test. Yield acknowledgement, text, completion, and failure events in precise order.
Cancellation deserves a direct test: start an effect, send the action that replaces or dismisses it, and prove late output does not mutate state.
Avoid asserting every internal helper. Tests should describe observable state, emitted actions, dependency calls that matter, and absence of forbidden effects. Controlled dependencies turn concurrent UI behavior into a small deterministic program.