.NET Agent Unit-Test and Coverage Requirements
These rules are mandatory and apply automatically -- the user does not need to ask for tests or for coverage. Honor them when planning work, when writing or editing tests, and when adding or changing production code.
Scope
- In scope (must be unit-tested): all production code in the
Coreproject (src/Agent/NewRelic/Agent/Core/) and theNewRelic.Agent.Extensionsproject (src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/). - Out of scope: the wrapper projects under
src/Agent/NewRelic/Agent/Extensions/Providers/Wrapper/*. They have no unit tests by design (covered by the Integration / Unbounded / Container test solutions). When adding non-trivial logic to a wrapper, lift it into a helper inNewRelic.Agent.Extensionsand unit-test the helper -- see the wrapper guidance intests/CLAUDE.mdand the top-levelCLAUDE.md.
Rule 1: New testable code gets unit tests in the same change
Adding or changing in-scope production code without accompanying unit tests is incomplete work, not a follow-up task. Write the tests as part of the same change, unprompted. Use TDD where practical: write the failing test first, see it fail, implement, see it pass.
Rule 2: Aim for 100% code coverage
When writing or modifying unit tests, cover every reachable line and branch of the code under test:
- Include error /
catchpaths, early returns, and boundary conditions (just-under / just-over a cap, empty / null inputs, first-and-last iterations). - The only acceptable uncovered code is a genuinely unreachable defensive guard
(for example an
IsNaNcheck on a value that the parser can never produce a NaN for, or adefault:no input can hit). Call these out explicitly rather than contorting tests to fake-cover dead code. - Do not pad coverage with assertion-free tests. Every test must verify behavior, not merely execute lines.
When writing implementation plans
Bake these rules into the plan so the implementer applies them without re-deriving them:
- In the plan's Global Constraints header, state: "All new/changed code in
CoreandNewRelic.Agent.Extensionsmust ship with unit tests in the same task; target 100% reachable line and branch coverage." - Every task that creates or modifies in-scope production code must include explicit TDD steps (write failing test -> run/fail -> implement -> run/pass -> commit) with the actual test code, not a "write tests for the above" placeholder.
- A task that only touches wrapper code (and cannot have its logic lifted into a helper) is the sole exception -- note that it is covered by integration tests instead.
Mechanics
Test layout, frameworks (NUnit + JustMock Lite, interfaces/virtual only), the
SolutionDir build caveat, and the "run against the built DLL for
NewRelic.Agent.Extensions.Tests" caveat are in the top-level CLAUDE.md
("Building and testing from the CLI", "Testing conventions") and
tests/CLAUDE.md.
Achieving coverage without piercing encapsulation
JustMock Lite mocks only interfaces and virtual members -- no sealed, static,
or non-virtual mocking -- and InternalsVisibleTo is banned in every
production and test assembly. So when in-scope code is hard to reach from a
test, do NOT widen visibility or expose internals to the test assembly. Make
the code coverable by refactoring the production type to expose a proper seam:
extract an interface, make the member virtual, inject a mockable dependency,
or lift the logic into a public helper. If a line is only reachable by mocking
a private/sealed/static member or via InternalsVisibleTo, the design -- not
the test -- is what must change.