Use the open-source free `coverlet` toolchain for .NET code coverage.
Scaffold a .NET Test Project
Create the first .NET test project. USE FOR: "solution has no tests", xUnit tests, Tests.csproj/ProjectReference, add an omitted test project to .sln/.slnx/.slnf, central packages, or tests missing from CI. DO NOT USE FOR: a suitable project already registered in the requested build entry point (stop) or migration.
Workflow
Step 1: Establish the repository contract
Inspect only the files needed to answer these questions:
- Which production project is in scope?
- What command does CI or the repository use to build and test?
- Does a suitable test project already reference that production project?
- Which test framework and runner do neighboring test projects use?
- Are package versions centrally managed by
Directory.Packages.props,
Directory.Build.props, global.json, or an MSBuild SDK declaration?
- Which target framework(s) must the test project compile against?
Treat a test project as suitable only when its target framework can reference the production project and its purpose matches the requested layer. Do not create a second test project merely because its name differs from your preferred name.
No-op stop condition: when a suitable project already exists and is registered in the requested build entry point, do not repair, normalize, convert, or replace the solution. If the user did not ask for tests yet, report the existing project path and stop with the workspace byte-for-byte unchanged.
Step 2: Choose one bounded project
Default to one test project per production project, named according to repository convention (Foo.Tests, Foo.UnitTests, and so on). For a vague multi-project request, start with the project that owns the user-visible behavior or has the highest-value untested logic; do not create one test project per source project without evidence that the repository wants that layout.
Match, in order:
- The user's explicit framework choice.
- Existing test projects in the same repository.
- Repository-wide package/SDK conventions.
- A standard SDK template only when the repository provides no convention.
Never mix frameworks in one test project. Never add package versions directly when central package management supplies them.
Step 3: Scaffold and reference the target
Use the matching dotnet new template (xunit, nunit, or mstest) rather than hand-writing template boilerplate. Then make only the repository-specific edits:
- Align target framework, nullable, implicit-usings, runner, and package style.
- Add a
ProjectReferenceto each production project directly exercised by
the planned tests. Do not reference every project in the solution.
- Remove template sample tests that do not test repository behavior.
For xUnit v3 projects that the repository runs through dotnet test, preserve or add both:
<OutputType>Exe</OutputType>
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
OutputType=Exe alone makes the self-hosted runner work with dotnet run; it is not evidence that the repository's dotnet test command can discover the tests.
Prefer dotnet add <test-project> reference <production-project> for project references. Inspect the resulting project file before continuing.
Step 4: Register with the real build entry point
Creating a .csproj is not enough. Add it to the exact solution artifact used by the repository:
.slnor.slnx:dotnet sln <solution> add <test-project>.slnf: add the project to the underlying solution and include it in the
filter used by the requested/CI test command.
- No solution artifact: keep the existing project-oriented workflow. Do not
create a solution solely for aesthetics unless the user asked for one.
Do not substitute a different solution file because it is easier to edit.
Step 5: Add a real smoke test
Replace template examples with the smallest smoke suite requested. The tests must:
- instantiate or invoke a real symbol from the referenced production project;
- assert a concrete result, not only non-null/truthiness;
- avoid network, wall-clock, process, and real filesystem dependencies.
These tests prove the project reference and discovery path. Stop after every behavior explicitly named by the user is covered; extra boundary permutations are out of scope here and belong to code-testing-agent.
Step 6: Verify direct and harness-level execution
Run, in this order:
dotnet test <test-project>to isolate scaffolding failures.- The repository's solution/root test command to prove CI discovery.
- A solution/project listing command to confirm the new project is registered.
If the direct command passes but the harness-level command discovers no new test, the scaffolding is incomplete. Fix registration before reporting success. Do not claim success from dotnet build alone.
Related skills
Write, run, or repair .NET tests that use MSTest.
Write, run, or repair .NET tests that use NUnit.