This guide explains how to integrate .NET unit tests into your Azure Pipelines to ensure code quality and stability. We'll cover setting up the build pipeline to discover and execute your tests.
.NET supports several popular unit testing frameworks, including:
Azure Pipelines can execute tests from any of these frameworks using the appropriate task.
We'll use a YAML pipeline to define the build and test stages. Here's a typical structure:
trigger:
- main
pool:
vmImage: 'windows-latest' # Or 'ubuntu-latest', 'macos-latest'
steps:
- task: UseDotNet@2
displayName: 'Use .NET SDK'
inputs:
packageType: 'sdk'
version: '6.x' # Specify your .NET SDK version
- task: DotNetCoreCLI@2
displayName: 'Restore Dependencies'
inputs:
command: 'restore'
projects: '**/*.sln'
- task: DotNetCoreCLI@2
displayName: 'Build Project'
inputs:
command: 'build'
projects: '**/*.sln'
arguments: '--configuration Release'
- task: DotNetCoreCLI@2
displayName: 'Run Unit Tests'
inputs:
command: 'test'
projects: '**/*[Tt]ests/*.csproj' # Adjust path if your test projects are elsewhere
arguments: '--configuration Release --logger trx --results-directory $(Agent.TempDirectory)'
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFormat: 'VSTest' # Or 'trx' if your logger produces trx files
testResultsFiles: '$(Agent.TempDirectory)/**/*.trx'
mergeTestResults: true
failTaskOnFailedTests: true
This section defines when the pipeline should run. In this case, it triggers on commits to the main
branch.
trigger:
- main
Specifies the agent pool to use for running the job. vmImage: 'windows-latest'
uses a Microsoft-hosted Windows agent.
pool:
vmImage: 'windows-latest'
The UseDotNet@2
task ensures the correct .NET SDK version is available on the agent.
- task: UseDotNet@2
displayName: 'Use .NET SDK'
inputs:
packageType: 'sdk'
version: '6.x'
The DotNetCoreCLI@2
task with the restore
command downloads all necessary NuGet packages.
- task: DotNetCoreCLI@2
displayName: 'Restore Dependencies'
inputs:
command: 'restore'
projects: '**/*.sln'
The build
command compiles your .NET solution.
- task: DotNetCoreCLI@2
displayName: 'Build Project'
inputs:
command: 'build'
projects: '**/*.sln'
arguments: '--configuration Release'
This is the core step for executing tests. The test
command finds and runs your unit tests.
projects: '**/*[Tt]ests/*.csproj'
: This pattern targets project files ending with "Tests.csproj" or "tests.csproj" in any directory. Adjust this if your test projects have different naming conventions or locations.arguments: '--logger trx --results-directory $(Agent.TempDirectory)'
:
--logger trx
: Configures the test runner to output results in the TRX format, which is compatible with the PublishTestResults
task.--results-directory $(Agent.TempDirectory)
: Specifies where to save the test results files. $(Agent.TempDirectory)
is a predefined variable that points to a temporary directory on the agent.
- task: DotNetCoreCLI@2
displayName: 'Run Unit Tests'
inputs:
command: 'test'
projects: '**/*[Tt]ests/*.csproj'
arguments: '--configuration Release --logger trx --results-directory $(Agent.TempDirectory)'
The PublishTestResults@2
task uploads the test results to Azure Pipelines, making them visible in the build summary and test results tab.
testResultsFormat: 'VSTest'
: Indicates the format of the test results. If you used --logger trx
, VSTest
is the correct format.testResultsFiles: '$(Agent.TempDirectory)/**/*.trx'
: Specifies the files to publish.failTaskOnFailedTests: true
: Configures the pipeline to fail if any tests do not pass.
- task: PublishTestResults@2
displayName: 'Publish Test Results'
inputs:
testResultsFormat: 'VSTest'
testResultsFiles: '$(Agent.TempDirectory)/**/*.trx'
mergeTestResults: true
failTaskOnFailedTests: true
The DotNetCoreCLI@2
task with the test
command is framework-agnostic. As long as your test projects are configured correctly for MSTest, NUnit, or xUnit.net, this task will discover and run them.
Ensure you have the NUnit NuGet packages installed in your test project:
dotnet add package NUnit
dotnet add package NUnit3TestAdapter
Ensure you have the xUnit.net NuGet packages installed:
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
After a successful pipeline run, you can view detailed test results:
Important: Ensure your .csproj
file for the test project correctly references the test framework and the project(s) under test.
For example, a test project's .csproj
might look like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<ProjectReference Include="..\..\src\MyApplication\MyApplication.csproj" />
</ItemGroup>
</Project>
To get code coverage reports, you can add the coverlet.collector
NuGet package to your test projects and include the --collect "Code coverage"
argument in your dotnet test
command.
- task: DotNetCoreCLI@2
displayName: 'Run Unit Tests with Coverage'
inputs:
command: 'test'
projects: '**/*[Tt]ests/*.csproj'
arguments: '--configuration Release --logger trx --results-directory $(Agent.TempDirectory) --collect "Code coverage"'
- task: PublishCodeCoverageResults@1
displayName: 'Publish Code Coverage Results'
inputs:
codeCoverageTool: 'Cobertura' # Or 'JaCoCo' depending on the collector
summaryFileLocation: '$(Agent.TempDirectory)/**/*.cobertura.xml' # Path might vary
Ensure you have the coverlet.collector
package installed in your test project for this to work.
You can filter which tests are run using the --filter
argument.
dotnet test --filter "Category=Integration"
dotnet test --filter "FullyQualifiedName~MyNamespace.MyClass.MyTestMethod"
You can pass these filters via the arguments
field in your YAML task.
projects
pattern in the DotNetCoreCLI@2
task to ensure it correctly targets your test project files.testResultsFiles
pattern in the PublishTestResults@2
task correctly matches the output files generated by the test runner.