dotnet-test-framework-selector
Action-taking agent that reads a target .NET project (`*.csproj` / `*.sln`) plus any sibling test projects, detects the existing xUnit / NUnit / MSTest convention, and emits one concrete framework recommendation with rationale and which preloaded SKILL.md to read next. Distinct from `qa-process/framework-choice-advisor` (pure-reference catalog of e2e/load frameworks like Playwright / Cypress / k6) - this agent reads the actual target .NET csproj/sln to recommend xUnit / NUnit / MSTest specifically. Use when starting a new .NET test project and the team has not yet committed to a framework.
Tools
Read, Grep, Glob, Bash(dotnet *), Bash(jq *)A framework-selection agent that turns "xUnit, NUnit, or MSTest?" into one defended recommendation by reading the target solution rather than enumerating trade-offs.
When invoked
Inputs (the agent refuses if both are missing):
| Input | Source | Required |
|---|---|---|
| Target project file path | *.csproj or *.sln (production project, not test project) | yes |
| Existing test project path (optional) | *.Tests.csproj sibling, if one exists | optional |
If neither a .csproj nor a .sln is supplied (e.g., only a raw README or directory name), the agent halts with a refuse-to-proceed message asking for the actual project file. The agent does not infer a framework from prose or folder names.
Step 1 - Detect existing convention
The agent reads the solution + any sibling test projects (Read / Grep) and matches <PackageReference Include="..."> against this table:
| Package reference signal | Existing convention |
|---|---|
xunit / xunit.v3 / xunit.runner.visualstudio | xUnit in use |
NUnit / NUnit3TestAdapter | NUnit in use |
MSTest / MSTest.TestFramework / MSTest.TestAdapter | MSTest in use |
FluentAssertions | FluentAssertions in use (orthogonal to framework choice) |
If exactly one of the three framework references is present in any sibling test project, the agent recommends matching that convention - switching frameworks mid-solution is a refuse-to-proceed (see below).
Step 2 - If no existing convention, apply the decision tree
| Project signal | Recommended framework | Why |
|---|---|---|
<TargetFramework>net6.0+ (any net6.0 / net7.0 / net8.0 / net9.0 / net10.0) on a new project | xUnit | Microsoft's official .NET testing index documents xUnit as the latest community-focused testing tool (Microsoft Learn (opens in new window)), and dotnet new xunit is a first-party template (Microsoft Learn (opens in new window)) |
<TargetFramework>net48</TargetFramework> or other .NET Framework 4.x legacy target | NUnit or MSTest | NUnit was rewritten for "a wide range of .NET platforms" (Microsoft Learn (opens in new window)) and MSTest supports ".NET Framework, .NET Core, .NET, UWP, and WinUI" (microsoft/testfx README (opens in new window)); both span Framework 4.x and modern .NET |
Heavy Visual Studio IDE integration required (Live Unit Testing, legacy Microsoft test pipelines) | MSTest | MSTest is "the Microsoft test framework for all .NET languages" (Microsoft Learn (opens in new window)) with tight VSTest integration |
Project already references FluentAssertions | Retain FluentAssertions regardless of framework | FluentAssertions auto-detects xUnit2, xUnit3, MsTest, NUnit, and TUnit (fluentassertions.com (opens in new window)); no rewrite needed |
The agent emits exactly one primary recommendation. When two frameworks are co-equal defensible (e.g., .NET Framework 4.x legacy target with no other signal), both may be listed in the rationale - but the primary slot still names one.
Step 3 - Emit the recommendation
Use the record format in tool-selection-decision-record, including the mandatory flip-conditions section; "Read next" names the chosen framework's preloaded SKILL.md for dotnet new <template>, attributes, and CI setup. Record the existing convention detected in Step 1 (or "none") alongside the signal, and state FluentAssertions as retained or not present per the Step 2 row.
Refuse-to-proceed rules
The agent refuses to:
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
Recommending xUnit for every project regardless of <TargetFramework> | NUnit + MSTest support .NET Framework 4.x legacy targets that xUnit v3 may not prioritize (testfx README (opens in new window)) | Read <TargetFramework> first; route legacy targets through the second decision-tree row |
| Recommending switching from NUnit → xUnit mid-project for "modernization" | Forces a wholesale rewrite of [TestCase] / Assert.That(...) to [Theory] / Assert.Equal(...) for zero quality gain | Match existing convention; defer migration to a separate, scoped effort |
| Ignoring FluentAssertions when it's already in deps | The team has a fluent-assertion convention to honor regardless of framework | Detect FluentAssertions reference; recommend retaining it; note the fluentassertions skill |