SuperAPI AI Directory

dotnet-testing-xunit-project-setup

Testing & quality

View repository

Updated 10-15 20:05

About this skill

xUnit Test Project Setup Guide

Project Structure Best Practices

Recommended Solution Structure

MyProject/
├── src/                          # 主程式碼目錄
│   └── MyProject.Core/
│       ├── MyProject.Core.csproj
│       ├── Calculator.cs
│       ├── Services/
│       └── Models/
├── tests/                        # 測試程式碼目錄
│   └── MyProject.Core.Tests/
│       ├── MyProject.Core.Tests.csproj
│       ├── CalculatorTests.cs
│       ├── Services/
│       └── Models/
└── MyProject.sln

Structural Principles:

  1. Separation of src and tests: Clearly distinguish production code from test code
  2. Naming Conventions: The test project name is {主專案名稱}.Tests
  3. Directory Correspondence: The folder structure of the test project should correspond to the structure of the main project
  4. One-to-One Mapping: Each main project should have a corresponding test project

Creating an xUnit Test Project

Method 1: Using the .NET CLI (Recommended)

Step 1: Create the solution and project

# 建立解決方案
dotnet new sln -n MyProject

# 建立主專案(類別庫)
dotnet new classlib -n MyProject.Core -o src/MyProject.Core

# 建立測試專案(xUnit 範本)
dotnet new xunit -n MyProject.Core.Tests -o tests/MyProject.Core.Tests

# 將專案加入解決方案
dotnet sln add src/MyProject.Core/MyProject.Core.csproj
dotnet sln add tests/MyProject.Core.Tests/MyProject.Core.Tests.csproj

# 建立專案參考(測試專案參考主專案)
dotnet add tests/MyProject.Core.Tests/MyProject.Core.Tests.csproj reference src/MyProject.Core/MyProject.Core.csproj

Step 2: Install the code coverage tool

# 切換到測試專案目錄
cd tests/MyProject.Core.Tests

# 安裝 coverlet.collector(用於收集程式碼覆蓋率)
dotnet add package coverlet.collector

Method 2: Using Visual Studio

  1. Create a solution

    • File → New → Project
    • Select "Blank Solution"
    • Name it after the project name
  2. Add the main project

    • Right-click the solution → Add → New Project
    • Select "Class Library"
    • Name it MyProject.Core
  3. Add the test project

    • Right-click the solution → Add → New Project
    • Search for and select "xUnit Test Project"
    • Name it MyProject.Core.Tests
  4. Set up project references

    • Right-click the test project → Add → Project Reference
    • Check the main project

csproj Configuration for an xUnit Test Project

Standard xUnit test project csproj

Please refer to the templates/xunit-test-project.csproj template file in the same directory.

Core Dependency Package Descriptions:

  1. xunit(2.9.3+)

    • The core package of the xUnit testing framework
    • Provides [Fact]、[Theory] and other test attributes
    • Includes the Assert class and assertion methods
  2. xunit.runner.visualstudio(3.0.0+)

    • Visual Studio Test Explorer integration
    • Allows tests to be discovered and run in VS Code, Visual Studio, and Rider
    • Supports real-time display of test results
  3. Microsoft.NET.Test.Sdk(18.3.0+)

    • The SDK for the .NET testing platform
    • Allows the dotnet test command to run tests
    • Supports test result reporting and test discovery
  4. coverlet.collector(8.0.0+)

    • Code coverage collection tool
    • Integrates with dotnet test integration
    • Generates coverage reports (supports formats such as Cobertura, OpenCover, etc.)

Important csproj Configuration Items

<PropertyGroup>
  <TargetFramework>net9.0</TargetFramework>
  <ImplicitUsings>enable</ImplicitUsings>
  <Nullable>enable</Nullable>
  <IsPackable>false</IsPackable>
  <IsTestProject>true</IsTestProject>
</PropertyGroup>

Configuration Descriptions:

  • IsPackable=false: The test project should not be packaged into a NuGet package
  • IsTestProject=true: Explicitly mark it as a test project so tools can identify it
  • Nullable=enable: Enable nullable reference type checking

Basic Structure of a Test Class

Standard test class template

namespace MyProject.Core.Tests;

public class CalculatorTests
{
    private readonly Calculator _calculator;

    // 建構函式:每個測試執行前都會被呼叫
    public CalculatorTests()
    {
        _calculator = new Calculator();
    }
}

Test Lifecycle (Important Concept)

xUnit's test isolation mechanism:

  1. Each test method creates a new instance of the test class
  2. Constructor: Called before each test method is executed
  3. Test method:Execute test logic
  4. Dispose():If the implementation IDisposable,is called after each test method executes

Execution order example:

執行 Test1:
  → 建構函式 → Test1 方法 → Dispose()

執行 Test2:
  → 建構函式 → Test2 方法 → Dispose()

This ensures test isolation,consistent with the FIRST principles of I (Independent)。

Run tests

Using the .NET CLI

# 建置專案
dotnet build

# 執行所有測試
dotnet test

# 執行測試並收集程式碼覆蓋率
dotnet test --collect:"XPlat Code Coverage"

# 執行特定測試專案
dotnet test tests/MyProject.Core.Tests/MyProject.Core.Tests.csproj

# 執行測試並產生詳細輸出
dotnet test --verbosity detailed

Run in the IDE

VS Code (requires the C# Dev Kit)

  1. Install C# Dev Kit
  2. Open Test Explorer
  3. Click the play button next to a test to run it

Visual Studio

  1. Open Test Explorer (Test → Test Explorer)
  2. Click "Run All" to run all tests
  3. You can right-click a single test to run or debug it

JetBrains Rider

  1. A green run icon appears next to the test method
  2. Click to run or debug the test
  3. Use the Unit Tests window to manage tests

Project reference setup principles

Reference direction rules

測試專案 → 主專案   (正確)
主專案 → 測試專案   (錯誤)

The test project should reference the main project, but the main project should absolutely never reference the test project.

Set up project references

# 讓測試專案參考主專案
dotnet add tests/MyProject.Core.Tests/MyProject.Core.Tests.csproj reference src/MyProject.Core/MyProject.Core.csproj

This is generated in the csproj:

<ItemGroup>
  <ProjectReference Include="..\..\src\MyProject.Core\MyProject.Core.csproj" />
</ItemGroup>

Advanced: Organizing multiple test projects

As the project grows, you may need multiple test projects:

MyProject/
├── src/
│   ├── MyProject.Core/
│   ├── MyProject.Web/
│   └── MyProject.Infrastructure/
├── tests/
│   ├── MyProject.Core.Tests/           # 單元測試
│   ├── MyProject.Web.Tests/            # Web 層測試
│   ├── MyProject.Infrastructure.Tests/ # 基礎設施測試
│   └── MyProject.Integration.Tests/    # 整合測試
└── MyProject.sln

Naming convention recommendations:

  • *.Tests - Unit tests
  • *.Integration.Tests - Integration tests
  • *.Acceptance.Tests - Acceptance tests
  • *.Performance.Tests - Performance tests

Naming conventions for real-world work projects

In real-world work projects, it is recommended to use a clearer naming format to distinguish test types:

Recommended naming format:

MyProject/
├── src/
│   ├── MyProject.Core/
│   └── MyProject.WebApi/
├── tests/
│   ├── MyProject.Core.Test.Unit/              # 單元測試(明確標示)
│   ├── MyProject.WebApi.Test.Unit/            # WebApi 單元測試
│   └── MyProject.WebApi.Test.Integration/     # WebApi 整合測試
└── MyProject.sln

Naming rules:

  • Unit tests:{專案名稱}.Test.Unit

    • Example:MyProject.Core.Test.Unit
    • Characteristics: Does not depend on external resources (databases, APIs, file systems, etc.)
    • Execution speed: Fast (millisecond level)
  • Integration tests:{專案名稱}.Test.Integration

    • Example:MyProject.WebApi.Test.Integration
    • Characteristics: Tests the integration of multiple components and may depend on external resources
    • Execution speed: Slower (second level)

Advantages of this naming:

  1. Clarity: You can tell the test type at a glance

  2. Execution strategy: Can be executed in stages in CI/CD

    # 快速回饋:只執行單元測試
    dotnet test --filter "FullyQualifiedName~.Test.Unit"
    
    # 完整驗證:執行整合測試
    dotnet test --filter "FullyQualifiedName~.Test.Integration"
    
  3. Dependency management: Integration tests can have different package dependencies (such as Testcontainers)

  4. Team collaboration: New members can quickly understand the project structure

CLI creation example:

# 建立單元測試專案
dotnet new xunit -n MyProject.Core.Test.Unit -o tests/MyProject.Core.Test.Unit
dotnet add tests/MyProject.Core.Test.Unit reference src/MyProject.Core

# 建立整合測試專案
dotnet new xunit -n MyProject.WebApi.Test.Integration -o tests/MyProject.WebApi.Test.Integration
dotnet add tests/MyProject.WebApi.Test.Integration reference src/MyProject.WebApi

Tip: Although this example uses .Tests format to simplify the explanation, in real projects it is strongly recommended to use .Test.Unit and .Test.Integration this clearer format.

Common issues and solutions

Q1: Test discovery fails, and Test Explorer cannot see the tests?

Checklist:

  1. Confirm that xunit.runner.visualstudio package is installed
  2. Confirm that Microsoft.NET.Test.Sdk package is installed
  3. Run dotnet build to rebuild
  4. Restart the IDE or reload Test Explorer

Q2: Tests can run in the CLI but cannot run in the IDE?

Solution:

  • Verify that the IDE has installed the relevant extensions (VS Code requires the C# Dev Kit)
  • Clear the cache: delete the bin/ and obj/ folders, then rebuild
  • Check whether the .csproj property in IsTestProject is true

Q3: How do I use an Internal class in a test project?

In the main project's .csproj or AssemblyInfo.cs add:

[assembly: InternalsVisibleTo("MyProject.Core.Tests")]

Or in the csproj:

<ItemGroup>
  <InternalsVisibleTo Include="MyProject.Core.Tests" />
</ItemGroup>

Template Files

Please refer to the template files in the same directory to quickly create a project:

  • templates/project-structure.md - Complete example of the project structure
  • templates/xunit-test-project.csproj - csproj template for an xUnit test project

Checklist

When creating an xUnit test project, please confirm the following items:

  • The test project is named {主專案名稱}.Tests
  • The test project is located in the tests/ directory
  • Installed the xunit、xunit.runner.visualstudio、Microsoft.NET.Test.Sdk package
  • Installed coverlet.collector for code coverage
  • The test project references the main project
  • IsPackable Set to false
  • IsTestProject Set to true
  • Can run dotnet test successfully
  • The IDE's Test Explorer can discover the tests

Output Format

  • Generate a complete xUnit test project structure (src/ and tests/ separated)
  • Generate the test project csproj file (including the required package references)
  • Provide the dotnet CLI command sequence for creation
  • Include the project reference settings and xunit.runner.json configuration (if needed)
  • Generate a basic test class template (.cs file)

Reference Resources

Original Article

The content of this skill is distilled from the "Old-School Software Engineer's Testing Training - 30-Day Challenge" article series:

Official Documentation

Related Skills

  • unit-test-fundamentals - Unit Testing Basics and the FIRST Principles
  • test-naming-conventions - Test Naming Conventions
  • code-coverage-analysis - Code Coverage Analysis