Skip to content

Test docs refactoring #45515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 26, 2025
Merged
20 changes: 20 additions & 0 deletions .openpublishing.redirection.core.json
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,10 @@
"source_path_from_root": "/docs/core/docker/publish-as-container.md",
"redirect_url": "/dotnet/core/containers/sdk-publish"
},
{
"source_path_from_root": "/docs/core/testing/unit-testing-fsharp-with-dotnet-test.md",
"redirect_url": "/dotnet/core/testing/unit-testing-fsharp-with-xunit"
},
{
"source_path_from_root": "/docs/core/testing/unit-testing-platform-architecture-capabilities.md",
"redirect_url": "/dotnet/core/testing/microsoft-testing-platform-architecture-capabilities"
Expand Down Expand Up @@ -1445,6 +1449,22 @@
{
"source_path_from_root": "/docs/core/testing/unit-testing-platform-vs-vstest.md",
"redirect_url": "/dotnet/core/testing/microsoft-testing-platform-vs-vstest"
},
{
"source_path_from_root": "/docs/core/testing/unit-testing-published-output.md",
"redirect_url": "/dotnet/core/tools/dotnet-vstest"
},
{
"source_path_from_root": "/docs/core/testing/unit-testing-visual-basic-with-dotnet-test.md",
"redirect_url": "/dotnet/core/testing/unit-testing-visual-basic-with-xunit"
},
{
"source_path_from_root": "/docs/core/testing/unit-testing-with-mstest.md",
"redirect_url": "/dotnet/core/testing/unit-testing-csharp-with-mstest"
},
{
"source_path_from_root": "/docs/core/testing/unit-testing-with-nunit.md",
"redirect_url": "/dotnet/core/testing/unit-testing-csharp-with-nunit"
}
]
}
4 changes: 2 additions & 2 deletions docs/architecture/maui/unit-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ Testing models and view models from MVVM applications is identical to testing an

Don't be tempted to make a unit test exercise more than one aspect of the unit's behavior. Doing so leads to tests that are difficult to read and update. It can also lead to confusion when interpreting a failure.

The eShop multi-platform app uses [MSTest](../../core/testing/unit-testing-with-mstest.md) to perform unit testing, which supports two different types of unit tests:
The eShop multi-platform app uses [MSTest](../../core/testing/unit-testing-csharp-with-mstest.md) to perform unit testing, which supports two different types of unit tests:

| Testing Type | Attribute | Description |
|-----------------|--------------|--------------------------------------------------------------|
| TestMethod | `TestMethod` | Defines the actual test method to run. |
| DataSource | `DataSource` | Tests that are only true for a particular set of data. |

The unit tests included with the eShop multi-platform app are TestMethod, so each unit test method is decorated with the `TestMethod` attribute. In addition to MSTest there are several other testing frameworks available including [NUnit](../../core/testing/unit-testing-with-nunit.md) and [xUnit](../../core/testing/unit-testing-with-dotnet-test.md).
The unit tests included with the eShop multi-platform app are TestMethod, so each unit test method is decorated with the `TestMethod` attribute. In addition to MSTest there are several other testing frameworks available including [NUnit](../../core/testing/unit-testing-csharp-with-nunit.md) and [xUnit](../../core/testing/unit-testing-csharp-with-xunit.md).

## Testing asynchronous functionality

Expand Down
2 changes: 1 addition & 1 deletion docs/azure/sdk/unit-testing-mocking.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,4 @@ Here's how it works:

* [Dependency injection in .NET](../../core/extensions/dependency-injection.md)
* [Unit testing best practices](../../core/testing/unit-testing-best-practices.md)
* [Unit testing C# in .NET using dotnet test and xUnit](../../core/testing/unit-testing-with-dotnet-test.md)
* [Unit testing C# in .NET using dotnet test and xUnit](../../core/testing/unit-testing-csharp-with-xunit.md)
10 changes: 5 additions & 5 deletions docs/core/testing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ The test framework is built on top of the test platform. It defines the set of a
For more information, see the following resources:

- [Microsoft.Testing.Platform support in MSTest (MSTest runner)](unit-testing-mstest-runner-intro.md)
- [Unit testing with C#](unit-testing-with-mstest.md)
- [Unit testing with C#](unit-testing-csharp-with-mstest.md)
- [Unit testing with F#](unit-testing-fsharp-with-mstest.md)
- [Unit testing with Visual Basic](unit-testing-visual-basic-with-mstest.md)

Expand All @@ -65,7 +65,7 @@ For more information, see the following resources:
For more information, see the following resources:

- [Microsoft.Testing.Platform support in NUnit (NUnit runner)](unit-testing-nunit-runner-intro.md)
- [Unit testing with C#](unit-testing-with-nunit.md)
- [Unit testing with C#](unit-testing-csharp-with-nunit.md)
- [Unit testing with F#](unit-testing-fsharp-with-nunit.md)
- [Unit testing with Visual Basic](unit-testing-visual-basic-with-nunit.md)

Expand All @@ -80,9 +80,9 @@ For more information, see the following resources:
For more information, see the following resources:

- [Microsoft.Testing.Platform support in xUnit.net v3](https://xunit.net/docs/getting-started/v3/microsoft-testing-platform)
- [Unit testing with C#](unit-testing-with-dotnet-test.md)
- [Unit testing with F#](unit-testing-fsharp-with-dotnet-test.md)
- [Unit testing with Visual Basic](unit-testing-visual-basic-with-dotnet-test.md)
- [Unit testing with C#](unit-testing-csharp-with-xunit.md)
- [Unit testing with F#](unit-testing-fsharp-with-xunit.md)
- [Unit testing with Visual Basic](unit-testing-visual-basic-with-xunit.md)

## Running tests

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Unit testing using MSTest sample

This sample is part of the [unit testing tutorial](https://learn.microsoft.com/dotnet/core/testing/unit-testing-with-mstest) for creating applications with unit tests included. See that topic for detailed steps on the code for this sample.
This sample is part of the [unit testing tutorial](https://learn.microsoft.com/dotnet/core/testing/unit-testing-csharp-with-mstest) for creating applications with unit tests included. See that topic for detailed steps on the code for this sample.

## Key features

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ Make the *PrimeService.Tests* directory the current directory and create a new p

```xml
<ItemGroup>
<PackageReference Include="MSTest" Version="3.8.3" />
<PackageReference Include="MSTest" Version="3.2.0" />
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.10.1" />
</ItemGroup>
```

Expand Down
230 changes: 230 additions & 0 deletions docs/core/testing/unit-testing-csharp-with-xunit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
---
title: Unit testing C# code in .NET using dotnet test and xUnit
description: Learn unit test concepts in C# and .NET through an interactive experience building a sample solution step-by-step using dotnet test and xUnit.
author: ardalis
ms.author: wiwagn
ms.date: 03/07/2024
---
# Unit testing C# in .NET using dotnet test and xUnit

This tutorial shows how to build a solution containing a unit test project and source code project. To follow the tutorial using a pre-built solution, [view or download the sample code](https://github.com/dotnet/samples/tree/main/core/getting-started/unit-testing-using-dotnet-test/). For download instructions, see [Samples and Tutorials](../../samples-and-tutorials/index.md#view-and-download-samples).

## Create the solution

In this section, a solution is created that contains the source and test projects. The completed solution has the following directory structure:

```txt
/unit-testing-using-dotnet-test
unit-testing-using-dotnet-test.sln
/PrimeService
PrimeService.cs
PrimeService.csproj
/PrimeService.Tests
PrimeService_IsPrimeShould.cs
PrimeServiceTests.csproj
```

The following instructions provide the steps to create the test solution. See [Commands to create test solution](#create-test-cmd) for instructions to create the test solution in one step.

* Open a shell window.
* Run the following command:

```dotnetcli
dotnet new sln -o unit-testing-using-dotnet-test
```

The [`dotnet new sln`](../tools/dotnet-new.md) command creates a new solution in the *unit-testing-using-dotnet-test* directory.
* Change directory to the *unit-testing-using-dotnet-test* folder.
* Run the following command:

```dotnetcli
dotnet new classlib -o PrimeService
```

The [`dotnet new classlib`](../tools/dotnet-new.md) command creates a new class library project in the *PrimeService* folder. The new class library will contain the code to be tested.
* Rename *Class1.cs* to *PrimeService.cs*.
* Replace the code in *PrimeService.cs* with the following code:

```csharp
using System;

namespace Prime.Services
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
throw new NotImplementedException("Not implemented.");
}
}
}
```

* The preceding code:
* Throws a <xref:System.NotImplementedException> with a message indicating it's not implemented.
* Is updated later in the tutorial.

<!-- preceding code shows an english bias. Message makes no sense outside english -->

* In the *unit-testing-using-dotnet-test* directory, run the following command to add the class library project to the solution:

```dotnetcli
dotnet sln add ./PrimeService/PrimeService.csproj
```

* Create the *PrimeService.Tests* project by running the following command:

```dotnetcli
dotnet new xunit -o PrimeService.Tests
```

* The preceding command:
* Creates the *PrimeService.Tests* project in the *PrimeService.Tests* directory. The test project uses [xUnit](https://xunit.net/) as the test library.
* Configures the test runner by adding the following `<PackageReference />`elements to the project file:
* `Microsoft.NET.Test.Sdk`
* `xunit`
* `xunit.runner.visualstudio`
* `coverlet.collector`

* Add the test project to the solution file by running the following command:

```dotnetcli
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
```

* Add the `PrimeService` class library as a dependency to the *PrimeService.Tests* project:

```dotnetcli
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
```

<a name="create-test-cmd"></a>

### Commands to create the solution

This section summarizes all the commands in the previous section. Skip this section if you've completed the steps in the previous section.

The following commands create the test solution on a Windows machine. For macOS and Unix, update the `ren` command to the OS version of `ren` to rename a file:

```dotnetcli
dotnet new sln -o unit-testing-using-dotnet-test
cd unit-testing-using-dotnet-test
dotnet new classlib -o PrimeService
ren .\PrimeService\Class1.cs PrimeService.cs
dotnet sln add ./PrimeService/PrimeService.csproj
dotnet new xunit -o PrimeService.Tests
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
```

Follow the instructions for "Replace the code in *PrimeService.cs* with the following code" in the previous section.

## Create a test

A popular approach in test driven development (TDD) is to write a (failing) test before implementing the target code. This tutorial uses the TDD approach. The `IsPrime` method is callable, but not implemented. A test call to `IsPrime` fails. With TDD, a test is written that is known to fail. The target code is updated to make the test pass. You keep repeating this approach, writing a failing test and then updating the target code to pass.

Update the *PrimeService.Tests* project:

* Delete *PrimeService.Tests/UnitTest1.cs*.
* Create a *PrimeService.Tests/PrimeService_IsPrimeShould.cs* file.
* Replace the code in *PrimeService_IsPrimeShould.cs* with the following code:

```csharp
using Xunit;
using Prime.Services;

namespace Prime.UnitTests.Services
{
public class PrimeService_IsPrimeShould
{
[Fact]
public void IsPrime_InputIs1_ReturnFalse()
{
var primeService = new PrimeService();
bool result = primeService.IsPrime(1);

Assert.False(result, "1 should not be prime");
}
}
}
```

The `[Fact]` attribute declares a test method that's run by the test runner. From the *PrimeService.Tests* folder, run `dotnet test`. The [dotnet test](../tools/dotnet-test.md) command builds both projects and runs the tests. The xUnit test runner contains the program entry point to run the tests. `dotnet test` starts the test runner using the unit test project.

The test fails because `IsPrime` hasn't been implemented. Using the TDD approach, write only enough code so this test passes. Update `IsPrime` with the following code:

```csharp
public bool IsPrime(int candidate)
{
if (candidate == 1)
{
return false;
}
throw new NotImplementedException("Not fully implemented.");
}
```

Run `dotnet test`. The test passes.

### Add more tests

Add prime number tests for 0 and -1. You could copy the test created in the preceding step and make copies of the following code to test 0 and -1.
But don't do it, as there's a better way.

```csharp
var primeService = new PrimeService();
bool result = primeService.IsPrime(1);

Assert.False(result, "1 should not be prime");
```

Copying test code when only a parameter changes results in code duplication and test bloat. The following xUnit attributes enable writing a suite of similar tests:

- `[Theory]` represents a suite of tests that execute the same code but have different input arguments.
- `[InlineData]` attribute specifies values for those inputs.

Rather than creating new tests, apply the preceding xUnit attributes to create a single theory. Replace the following code:

```csharp
[Fact]
public void IsPrime_InputIs1_ReturnFalse()
{
var primeService = new PrimeService();
bool result = primeService.IsPrime(1);

Assert.False(result, "1 should not be prime");
}
```

with the following code:

:::code language="csharp" source="../../../samples/snippets/core/testing/unit-testing-using-dotnet-test/csharp/PrimeService.Tests/PrimeService_IsPrimeShould.cs" id="Sample_TestCode":::

In the preceding code, `[Theory]` and `[InlineData]` enable testing several values less than two. Two is the smallest prime number.

Add the following code after the class declaration and before the `[Theory]` attribute:

:::code language="csharp" source="../../../samples/snippets/core/testing/unit-testing-using-dotnet-test/csharp/PrimeService.Tests/PrimeService_IsPrimeShould.cs" id="Sample_InitCode":::

Run `dotnet test`, and two of the tests fail. To make all of the tests pass, update the `IsPrime` method with the following code:

```csharp
public bool IsPrime(int candidate)
{
if (candidate < 2)
{
return false;
}
throw new NotImplementedException("Not fully implemented.");
}
```

Following the TDD approach, add more failing tests, then update the target code. See the [finished version of the tests](https://github.com/dotnet/samples/blob/main/core/getting-started/unit-testing-using-dotnet-test/PrimeService.Tests/PrimeService_IsPrimeShould.cs) and the [complete implementation of the library](https://github.com/dotnet/samples/blob/main/core/getting-started/unit-testing-using-dotnet-test/PrimeService/PrimeService.cs).

The completed `IsPrime` method is not an efficient algorithm for testing primality.

### Additional resources

- [xUnit.net official site](https://xunit.net)
- [Testing controller logic in ASP.NET Core](/aspnet/core/mvc/controllers/testing)
- [`dotnet add reference`](../tools/dotnet-add-reference.md)
2 changes: 1 addition & 1 deletion docs/core/testing/unit-testing-mstest-sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ For more information, see [Use MSBuild project SDKs](/visualstudio/msbuild/how-t

When you `build` the project, all the needed components are restored and installed using the standard NuGet workflow set by your project.

You don't need anything else to build and run your tests and you can use the same tooling (for example, `dotnet test` or Visual Studio) used by a ["classic" MSTest project](./unit-testing-with-mstest.md).
You don't need anything else to build and run your tests and you can use the same tooling (for example, `dotnet test` or Visual Studio) used by a ["classic" MSTest project](./unit-testing-csharp-with-mstest.md).

> [!IMPORTANT]
> By switching to the `MSTest.Sdk`, you opt in to using the [MSTest runner](./unit-testing-mstest-runner-intro.md), including with [dotnet test](./microsoft-testing-platform-integration-dotnet-test.md#dotnet-test---microsofttestingplatform-mode). That requires modifying your CI and local CLI calls, and also impacts the available entries of the _.runsettings_. You can use `MSTest.Sdk` and still keep the old integrations and tools by instead switching the [runner](#select-the-runner).
Expand Down
34 changes: 0 additions & 34 deletions docs/core/testing/unit-testing-published-output.md

This file was deleted.

Loading