dotnet-add-testing

📁 novotnyllc/dotnet-artisan 📅 4 days ago
4
总安装量
4
周安装量
#47887
全站排名
安装命令
npx skills add https://github.com/novotnyllc/dotnet-artisan --skill dotnet-add-testing

Agent 安装分布

gemini-cli 4
github-copilot 4
codex 4
kimi-cli 4
cursor 4
amp 4

Skill 文档

dotnet-add-testing

Add test infrastructure scaffolding to an existing .NET project. Creates test projects with xUnit, configures code coverage with coverlet, and sets up the conventional directory structure.

Scope

  • Test project creation with xUnit and coverlet
  • Conventional directory structure (tests/ mirroring src/)
  • Project reference wiring and test SDK configuration

Out of scope

  • In-depth testing patterns (xUnit v3, WebApplicationFactory, UI testing) — see [skill:dotnet-testing-strategy]

Prerequisites: Run [skill:dotnet-version-detection] first to determine SDK version and TFM. Run [skill:dotnet-project-analysis] to understand existing solution structure.

Cross-references: [skill:dotnet-project-structure] for overall solution layout conventions, [skill:dotnet-scaffold-project] which includes test scaffolding in new projects, [skill:dotnet-add-analyzers] for test-specific analyzer suppressions.


Test Project Structure

Follow the convention of mirroring src/ project names under tests/:

MyApp/
├── src/
│   ├── MyApp.Core/
│   ├── MyApp.Api/
│   └── MyApp.Infrastructure/
└── tests/
    ├── MyApp.Core.UnitTests/
    ├── MyApp.Api.UnitTests/
    ├── MyApp.Api.IntegrationTests/
    └── Directory.Build.props          # Test-specific build settings

Naming conventions:

  • *.UnitTests — isolated tests with no external dependencies
  • *.IntegrationTests — tests that use real infrastructure (database, HTTP, file system)
  • *.FunctionalTests — end-to-end tests through the full application stack

Step 1: Create the Test Project

# Create xUnit test project
dotnet new xunit -n MyApp.Core.UnitTests -o tests/MyApp.Core.UnitTests

# Add to solution
dotnet sln add tests/MyApp.Core.UnitTests/MyApp.Core.UnitTests.csproj

# Add reference to the project under test
dotnet add tests/MyApp.Core.UnitTests/MyApp.Core.UnitTests.csproj \
  reference src/MyApp.Core/MyApp.Core.csproj

Clean Up Generated Project

Remove properties already defined in Directory.Build.props:

<!-- tests/MyApp.Core.UnitTests/MyApp.Core.UnitTests.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" />
    <PackageReference Include="xunit.v3" />
    <PackageReference Include="xunit.runner.visualstudio" />
    <PackageReference Include="coverlet.collector" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\src\MyApp.Core\MyApp.Core.csproj" />
  </ItemGroup>
</Project>

With CPM, Version attributes are managed in Directory.Packages.props. Remove them from the generated .csproj.


Step 2: Add Test-Specific Build Properties

Create tests/Directory.Build.props to customize settings for all test projects:

<!-- tests/Directory.Build.props -->
<Project>
  <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
  <PropertyGroup>
    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
    <!-- Use Microsoft.Testing.Platform v2 runner (requires Microsoft.NET.Test.Sdk 17.13+/18.x) -->
    <UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
    <!-- Relax strictness for test projects -->
    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
  </PropertyGroup>
</Project>

This imports the root Directory.Build.props (for shared settings like Nullable, ImplicitUsings, LangVersion) and overrides test-specific properties.


Step 3: Register Test Packages in CPM

Add test package versions to Directory.Packages.props:

<!-- In Directory.Packages.props -->
<ItemGroup>
  <!-- Test packages -->
  <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
  <PackageVersion Include="xunit.v3" Version="3.2.2" />
  <PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
  <PackageVersion Include="coverlet.collector" Version="8.0.0" />
</ItemGroup>

Optional: Mocking Library

Add a mocking library if the project needs test doubles:

<PackageVersion Include="NSubstitute" Version="5.3.0" />

Or for assertion libraries:

<PackageVersion Include="FluentAssertions" Version="8.0.1" />

Step 4: Configure Code Coverage

Coverlet (Collector Mode)

The coverlet.collector package integrates with dotnet test via the data collector. No additional configuration is needed for basic coverage.

Generate coverage reports:

# Collect coverage (Cobertura format by default)
dotnet test --collect:"XPlat Code Coverage"

# Results appear in TestResults/*/coverage.cobertura.xml

Coverage Thresholds

For CI enforcement, use coverlet.msbuild for threshold checks:

<!-- In test csproj or tests/Directory.Build.props -->
<PackageReference Include="coverlet.msbuild" />
# Enforce minimum coverage threshold
dotnet test /p:CollectCoverage=true \
  /p:CoverageOutputFormat=cobertura \
  /p:Threshold=80 \
  /p:ThresholdType=line

Coverage Report Generation

Use reportgenerator for human-readable HTML reports:

# Install globally
dotnet tool install -g dotnet-reportgenerator-globaltool

# Generate HTML report
reportgenerator \
  -reports:"tests/**/coverage.cobertura.xml" \
  -targetdir:coverage-report \
  -reporttypes:Html

Step 5: Add EditorConfig Overrides for Tests

In the root .editorconfig, add test-specific relaxations:

[tests/**.cs]
# Allow underscores in test method names (Given_When_Then or Should_Behavior)
dotnet_diagnostic.CA1707.severity = none

# Test parameters are validated by the framework
dotnet_diagnostic.CA1062.severity = none

# ConfigureAwait not relevant in test context
dotnet_diagnostic.CA2007.severity = none

# Tests often have intentionally unused variables for assertions
dotnet_diagnostic.IDE0059.severity = suggestion

Step 6: Write a Starter Test

Replace the template-generated UnitTest1.cs with a properly structured test:

namespace MyApp.Core.UnitTests;

public class SampleServiceTests
{
    [Fact]
    public void Method_Condition_ExpectedResult()
    {
        // Arrange
        var sut = new SampleService();

        // Act
        var result = sut.DoWork();

        // Assert
        Assert.NotNull(result);
    }

    [Theory]
    [InlineData(1, 2, 3)]
    [InlineData(0, 0, 0)]
    [InlineData(-1, 1, 0)]
    public void Add_TwoNumbers_ReturnsSum(int a, int b, int expected)
    {
        var result = Calculator.Add(a, b);
        Assert.Equal(expected, result);
    }
}

Test Naming Convention

Use the pattern Method_Condition_ExpectedResult:

  • CreateUser_WithValidInput_ReturnsUser
  • GetById_WhenNotFound_ReturnsNull
  • Delete_WithoutPermission_ThrowsUnauthorized

Verify

After adding test infrastructure, verify everything works:

# Restore (regenerate lock files if using CPM)
dotnet restore

# Build (verifies project references and analyzer config)
dotnet build --no-restore

# Run tests
dotnet test --no-build

# Run with coverage
dotnet test --collect:"XPlat Code Coverage"

Adding Integration Test Projects

For integration tests that need WebApplicationFactory or database access:

dotnet new xunit -n MyApp.Api.IntegrationTests -o tests/MyApp.Api.IntegrationTests
dotnet sln add tests/MyApp.Api.IntegrationTests/MyApp.Api.IntegrationTests.csproj
dotnet add tests/MyApp.Api.IntegrationTests/MyApp.Api.IntegrationTests.csproj \
  reference src/MyApp.Api/MyApp.Api.csproj

Add integration test packages to CPM (match the Microsoft.AspNetCore.Mvc.Testing major version to the target framework — e.g., 8.x for net8.0, 9.x for net9.0, 10.x for net10.0):

<!-- Version must match the project's target framework major version -->
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
<PackageVersion Include="Testcontainers" Version="4.3.0" />

Integration test depth (WebApplicationFactory patterns, test containers, database fixtures) — see [skill:dotnet-integration-testing].


What’s Next

This skill covers test project scaffolding. For deeper testing guidance:

  • xUnit v3 features and patterns — [skill:dotnet-xunit]
  • Integration testing with WebApplicationFactory — [skill:dotnet-integration-testing]
  • UI testing (Blazor, MAUI, Uno) — [skill:dotnet-blazor-testing], [skill:dotnet-maui-testing], [skill:dotnet-uno-testing]
  • Snapshot testing — [skill:dotnet-snapshot-testing]
  • Test quality and coverage enforcement — [skill:dotnet-test-quality]
  • CI test reporting — [skill:dotnet-add-ci] for starter, [skill:dotnet-gha-build-test] and [skill:dotnet-ado-build-test] for advanced

References