Moq, strict vs loose usage
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Moq, Loose and Strict control how a mock reacts to calls you did not configure explicitly. Loose returns default values and lets the test continue. Strict throws as soon as code under test touches an unexpected member. The right choice depends on whether the test is mainly about the final output or about enforcing an interaction contract.
Loose Behavior Is Tolerant by Design
Loose mode is the default because it keeps many tests lightweight. If a method was not set up, Moq supplies a default value instead of failing immediately.
This is useful when the collaborator details are not the main point of the test and the mock exists only to keep the object graph simple.
Strict Behavior Fails Fast on Unexpected Calls
Strict mode is more defensive. Every interaction the code under test performs must be set up in advance, or the test fails immediately.
That makes strict mocks useful when calling the collaborator in the right way is part of the behavior being tested.
Use Loose Mode for Output-Focused Tests
If the test mainly cares about the observable result and not every collaborator interaction, loose mode is often simpler.
Here, strict setup would add noise without improving the test’s value much.
Use Strict Mode When Interaction Is the Contract
Strict mode becomes useful when the test exists specifically to verify that an interaction happened and happened correctly.
If the service makes the wrong call, the test fails immediately instead of silently accepting a default.
A Hybrid Strategy Usually Works Best
Most test suites should not choose one behavior globally. A more practical rule is:
- default to loose for low-risk collaborators,
- use strict for important side-effect boundaries such as auditing, payment, messaging, or security decisions,
- and verify only the interactions that matter to the business behavior.
That avoids the two bad extremes: brittle strict-everywhere tests and overly permissive loose-everywhere tests.
Async Tests Still Need the Same Discipline
With async methods, the main rule is to await the code under test before verification.
The strict-versus-loose decision does not change, but premature verification is a common source of flaky tests.
Common Pitfalls
- Setting every mock to strict and making tests fail on harmless internal refactors.
- Leaving everything loose and missing important unexpected calls.
- Verifying incidental details that are not part of the behavior under test.
- Using strict mocks without clear setups and then blaming Moq for test fragility.
- Verifying async interactions before awaited work has actually completed.
Summary
- '
Loosemode returns defaults for unconfigured calls and is good for output-focused tests.' - '
Strictmode fails on unexpected calls and is good for interaction-contract tests.' - Most test suites benefit from a mixed strategy rather than one universal rule.
- Verify only interactions that matter to correctness.
- Keep async tests properly awaited before verification.

