Skip to content

Commit 643d410

Browse files
Test docs refactoring (#45515)
* Test docs refactoring * Conceptual doc for dotnet test * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Mariam Abdullah <[email protected]> * Apply suggestions from code review Co-authored-by: Mariam Abdullah <[email protected]> * Update docs/core/testing/unit-testing-with-dotnet-test.md Co-authored-by: Mariam Abdullah <[email protected]> * Update docs/core/testing/unit-testing-with-dotnet-test.md Co-authored-by: Mariam Abdullah <[email protected]> * Apply suggestions from code review Co-authored-by: Mariam Abdullah <[email protected]> * Update docs/core/testing/unit-testing-with-dotnet-test.md Co-authored-by: Mariam Abdullah <[email protected]> * Apply suggestions from code review Co-authored-by: Mariam Abdullah <[email protected]> * Update docs/core/testing/unit-testing-with-dotnet-test.md Co-authored-by: Mariam Abdullah <[email protected]> --------- Co-authored-by: Mariam Abdullah <[email protected]>
1 parent 7e3aadc commit 643d410

File tree

20 files changed

+320
-261
lines changed

20 files changed

+320
-261
lines changed

.openpublishing.redirection.core.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,6 +1358,10 @@
13581358
"source_path_from_root": "/docs/core/docker/publish-as-container.md",
13591359
"redirect_url": "/dotnet/core/containers/sdk-publish"
13601360
},
1361+
{
1362+
"source_path_from_root": "/docs/core/testing/unit-testing-fsharp-with-dotnet-test.md",
1363+
"redirect_url": "/dotnet/core/testing/unit-testing-fsharp-with-xunit"
1364+
},
13611365
{
13621366
"source_path_from_root": "/docs/core/testing/unit-testing-platform-architecture-capabilities.md",
13631367
"redirect_url": "/dotnet/core/testing/microsoft-testing-platform-architecture-capabilities"
@@ -1445,6 +1449,22 @@
14451449
{
14461450
"source_path_from_root": "/docs/core/testing/unit-testing-platform-vs-vstest.md",
14471451
"redirect_url": "/dotnet/core/testing/microsoft-testing-platform-vs-vstest"
1452+
},
1453+
{
1454+
"source_path_from_root": "/docs/core/testing/unit-testing-published-output.md",
1455+
"redirect_url": "/dotnet/core/tools/dotnet-vstest"
1456+
},
1457+
{
1458+
"source_path_from_root": "/docs/core/testing/unit-testing-visual-basic-with-dotnet-test.md",
1459+
"redirect_url": "/dotnet/core/testing/unit-testing-visual-basic-with-xunit"
1460+
},
1461+
{
1462+
"source_path_from_root": "/docs/core/testing/unit-testing-with-mstest.md",
1463+
"redirect_url": "/dotnet/core/testing/unit-testing-csharp-with-mstest"
1464+
},
1465+
{
1466+
"source_path_from_root": "/docs/core/testing/unit-testing-with-nunit.md",
1467+
"redirect_url": "/dotnet/core/testing/unit-testing-csharp-with-nunit"
14481468
}
14491469
]
14501470
}

docs/architecture/maui/unit-testing.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@ Testing models and view models from MVVM applications is identical to testing an
6262

6363
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.
6464

65-
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:
65+
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:
6666

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

72-
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).
72+
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).
7373

7474
## Testing asynchronous functionality
7575

docs/azure/sdk/unit-testing-mocking.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,4 @@ Here's how it works:
265265

266266
* [Dependency injection in .NET](../../core/extensions/dependency-injection.md)
267267
* [Unit testing best practices](../../core/testing/unit-testing-best-practices.md)
268-
* [Unit testing C# in .NET using dotnet test and xUnit](../../core/testing/unit-testing-with-dotnet-test.md)
268+
* [Unit testing C# in .NET using dotnet test and xUnit](../../core/testing/unit-testing-csharp-with-xunit.md)

docs/core/testing/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The test framework is built on top of the test platform. It defines the set of a
5454
For more information, see the following resources:
5555

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

@@ -65,7 +65,7 @@ For more information, see the following resources:
6565
For more information, see the following resources:
6666

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

@@ -80,9 +80,9 @@ For more information, see the following resources:
8080
For more information, see the following resources:
8181

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

8787
## Running tests
8888

docs/core/testing/snippets/unit-testing-using-mstest/csharp/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Unit testing using MSTest sample
22

3-
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.
3+
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.
44

55
## Key features
66

docs/core/testing/unit-testing-with-mstest.md renamed to docs/core/testing/unit-testing-csharp-with-mstest.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ Make the *PrimeService.Tests* directory the current directory and create a new p
6565

6666
```xml
6767
<ItemGroup>
68-
<PackageReference Include="MSTest" Version="3.8.3" />
68+
<PackageReference Include="MSTest" Version="3.2.0" />
69+
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.10.1" />
6970
</ItemGroup>
7071
```
7172

File renamed without changes.
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
---
2+
title: Unit testing C# code in .NET using dotnet test and xUnit
3+
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.
4+
author: ardalis
5+
ms.author: wiwagn
6+
ms.date: 03/07/2024
7+
---
8+
# Unit testing C# in .NET using dotnet test and xUnit
9+
10+
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).
11+
12+
## Create the solution
13+
14+
In this section, a solution is created that contains the source and test projects. The completed solution has the following directory structure:
15+
16+
```txt
17+
/unit-testing-using-dotnet-test
18+
unit-testing-using-dotnet-test.sln
19+
/PrimeService
20+
PrimeService.cs
21+
PrimeService.csproj
22+
/PrimeService.Tests
23+
PrimeService_IsPrimeShould.cs
24+
PrimeServiceTests.csproj
25+
```
26+
27+
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.
28+
29+
* Open a shell window.
30+
* Run the following command:
31+
32+
```dotnetcli
33+
dotnet new sln -o unit-testing-using-dotnet-test
34+
```
35+
36+
The [`dotnet new sln`](../tools/dotnet-new.md) command creates a new solution in the *unit-testing-using-dotnet-test* directory.
37+
* Change directory to the *unit-testing-using-dotnet-test* folder.
38+
* Run the following command:
39+
40+
```dotnetcli
41+
dotnet new classlib -o PrimeService
42+
```
43+
44+
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.
45+
* Rename *Class1.cs* to *PrimeService.cs*.
46+
* Replace the code in *PrimeService.cs* with the following code:
47+
48+
```csharp
49+
using System;
50+
51+
namespace Prime.Services
52+
{
53+
public class PrimeService
54+
{
55+
public bool IsPrime(int candidate)
56+
{
57+
throw new NotImplementedException("Not implemented.");
58+
}
59+
}
60+
}
61+
```
62+
63+
* The preceding code:
64+
* Throws a <xref:System.NotImplementedException> with a message indicating it's not implemented.
65+
* Is updated later in the tutorial.
66+
67+
<!-- preceding code shows an english bias. Message makes no sense outside english -->
68+
69+
* In the *unit-testing-using-dotnet-test* directory, run the following command to add the class library project to the solution:
70+
71+
```dotnetcli
72+
dotnet sln add ./PrimeService/PrimeService.csproj
73+
```
74+
75+
* Create the *PrimeService.Tests* project by running the following command:
76+
77+
```dotnetcli
78+
dotnet new xunit -o PrimeService.Tests
79+
```
80+
81+
* The preceding command:
82+
* Creates the *PrimeService.Tests* project in the *PrimeService.Tests* directory. The test project uses [xUnit](https://xunit.net/) as the test library.
83+
* Configures the test runner by adding the following `<PackageReference />`elements to the project file:
84+
* `Microsoft.NET.Test.Sdk`
85+
* `xunit`
86+
* `xunit.runner.visualstudio`
87+
* `coverlet.collector`
88+
89+
* Add the test project to the solution file by running the following command:
90+
91+
```dotnetcli
92+
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
93+
```
94+
95+
* Add the `PrimeService` class library as a dependency to the *PrimeService.Tests* project:
96+
97+
```dotnetcli
98+
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
99+
```
100+
101+
<a name="create-test-cmd"></a>
102+
103+
### Commands to create the solution
104+
105+
This section summarizes all the commands in the previous section. Skip this section if you've completed the steps in the previous section.
106+
107+
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:
108+
109+
```dotnetcli
110+
dotnet new sln -o unit-testing-using-dotnet-test
111+
cd unit-testing-using-dotnet-test
112+
dotnet new classlib -o PrimeService
113+
ren .\PrimeService\Class1.cs PrimeService.cs
114+
dotnet sln add ./PrimeService/PrimeService.csproj
115+
dotnet new xunit -o PrimeService.Tests
116+
dotnet add ./PrimeService.Tests/PrimeService.Tests.csproj reference ./PrimeService/PrimeService.csproj
117+
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
118+
```
119+
120+
Follow the instructions for "Replace the code in *PrimeService.cs* with the following code" in the previous section.
121+
122+
## Create a test
123+
124+
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.
125+
126+
Update the *PrimeService.Tests* project:
127+
128+
* Delete *PrimeService.Tests/UnitTest1.cs*.
129+
* Create a *PrimeService.Tests/PrimeService_IsPrimeShould.cs* file.
130+
* Replace the code in *PrimeService_IsPrimeShould.cs* with the following code:
131+
132+
```csharp
133+
using Xunit;
134+
using Prime.Services;
135+
136+
namespace Prime.UnitTests.Services
137+
{
138+
public class PrimeService_IsPrimeShould
139+
{
140+
[Fact]
141+
public void IsPrime_InputIs1_ReturnFalse()
142+
{
143+
var primeService = new PrimeService();
144+
bool result = primeService.IsPrime(1);
145+
146+
Assert.False(result, "1 should not be prime");
147+
}
148+
}
149+
}
150+
```
151+
152+
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.
153+
154+
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:
155+
156+
```csharp
157+
public bool IsPrime(int candidate)
158+
{
159+
if (candidate == 1)
160+
{
161+
return false;
162+
}
163+
throw new NotImplementedException("Not fully implemented.");
164+
}
165+
```
166+
167+
Run `dotnet test`. The test passes.
168+
169+
### Add more tests
170+
171+
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.
172+
But don't do it, as there's a better way.
173+
174+
```csharp
175+
var primeService = new PrimeService();
176+
bool result = primeService.IsPrime(1);
177+
178+
Assert.False(result, "1 should not be prime");
179+
```
180+
181+
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:
182+
183+
- `[Theory]` represents a suite of tests that execute the same code but have different input arguments.
184+
- `[InlineData]` attribute specifies values for those inputs.
185+
186+
Rather than creating new tests, apply the preceding xUnit attributes to create a single theory. Replace the following code:
187+
188+
```csharp
189+
[Fact]
190+
public void IsPrime_InputIs1_ReturnFalse()
191+
{
192+
var primeService = new PrimeService();
193+
bool result = primeService.IsPrime(1);
194+
195+
Assert.False(result, "1 should not be prime");
196+
}
197+
```
198+
199+
with the following code:
200+
201+
:::code language="csharp" source="../../../samples/snippets/core/testing/unit-testing-using-dotnet-test/csharp/PrimeService.Tests/PrimeService_IsPrimeShould.cs" id="Sample_TestCode":::
202+
203+
In the preceding code, `[Theory]` and `[InlineData]` enable testing several values less than two. Two is the smallest prime number.
204+
205+
Add the following code after the class declaration and before the `[Theory]` attribute:
206+
207+
:::code language="csharp" source="../../../samples/snippets/core/testing/unit-testing-using-dotnet-test/csharp/PrimeService.Tests/PrimeService_IsPrimeShould.cs" id="Sample_InitCode":::
208+
209+
Run `dotnet test`, and two of the tests fail. To make all of the tests pass, update the `IsPrime` method with the following code:
210+
211+
```csharp
212+
public bool IsPrime(int candidate)
213+
{
214+
if (candidate < 2)
215+
{
216+
return false;
217+
}
218+
throw new NotImplementedException("Not fully implemented.");
219+
}
220+
```
221+
222+
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).
223+
224+
The completed `IsPrime` method is not an efficient algorithm for testing primality.
225+
226+
### Additional resources
227+
228+
- [xUnit.net official site](https://xunit.net)
229+
- [Testing controller logic in ASP.NET Core](/aspnet/core/mvc/controllers/testing)
230+
- [`dotnet add reference`](../tools/dotnet-add-reference.md)
File renamed without changes.

docs/core/testing/unit-testing-mstest-sdk.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ For more information, see [Use MSBuild project SDKs](/visualstudio/msbuild/how-t
6161

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

64-
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).
64+
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).
6565

6666
> [!IMPORTANT]
6767
> 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).

0 commit comments

Comments
 (0)