Skip to content

Commit

Permalink
Adds NUnit test tutorial for .NET Core C# (#3856)
Browse files Browse the repository at this point in the history
* Adds NUnit sample C# test project

* Adds NUnit C# testing to the Unit Testing in .NET Core page

* Removed copy of code sample that gets pulled in from the samples

* Remove the asset id

* Changes based on PR code review
  • Loading branch information
rprouse authored and BillWagner committed Dec 5, 2017
1 parent 89af611 commit 311c92d
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 1 deletion.
3 changes: 2 additions & 1 deletion docs/core/testing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ When writing unit tests, be careful you don’t accidentally introduce dependenc

Learn more about unit testing in .NET Core projects:

Unit Test projects for .NET Core are supported for [C#](../../csharp/index.md), [F#](../../fsharp/index.md) and [Visual Basic](../../visual-basic/index.md). You can also choose between [xUnit](http://xunit.github.io) and [MSTest](https://github.com/Microsoft/vstest-docs).
Unit Test projects for .NET Core are supported for [C#](../../csharp/index.md), [F#](../../fsharp/index.md) and [Visual Basic](../../visual-basic/index.md). You can also choose between [xUnit](http://xunit.github.io), [NUnit](http://nunit.org) and [MSTest](https://github.com/Microsoft/vstest-docs).

You can read about those combinations in these walkthroughs:

* Create unit tests using [*XUnit* and *C#* with the .NET Core CLI](unit-testing-with-dotnet-test.md).
* Create unit tests using [*NUnit* and *C#* with the .NET Core CLI](unit-testing-with-nunit.md).
* Create unit tests using [*MSTest* and *C#* with the .NET Core CLI](unit-testing-with-mstest.md).
* Create unit tests using [*XUnit* and *F#* with the .NET Core CLI](unit-testing-fsharp-with-dotnet-test.md).
* Create unit tests using [*MSTest* and *F#* with the .NET Core CLI](unit-testing-fsharp-with-mstest.md).
Expand Down
166 changes: 166 additions & 0 deletions docs/core/testing/unit-testing-with-nunit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
---
title: Unit testing C# with NUnit and .NET Core
description: Learn unit test concepts in C# and .NET Core through an interactive experience building a sample solution step-by-step using dotnet test and NUnit.
keywords: NUnit, .NET, .NET Core
author: rprouse
ms.date: 12/01/2017
ms.topic: article
ms.prod: .net-core
ms.devlang: dotnet
---

# Unit testing C# with NUnit and .NET Core

This tutorial takes you through an interactive experience building a sample solution step-by-step to learn unit testing concepts. If you prefer to follow the tutorial using a pre-built solution, [view or download the sample code](https://github.com/dotnet/docs/blob/master/samples/core/getting-started/unit-testing-using-nunit/) before you begin. For download instructions, see [Samples and Tutorials](../../samples-and-tutorials/index.md#viewing-and-downloading-samples).

## Creating the source project

Open a shell window. Create a directory called *unit-testing-using-nunit* to hold the solution. Inside this new directory, run [`dotnet new sln`](../tools/dotnet-new.md) to create
a new solution file for the class library and the test project. Next, create a *PrimeService* directory. The following outline shows the directory and file structure thus far:

```
/unit-testing-using-nunit
unit-testing-using-nunit.sln
/PrimeService
```

Make *PrimeService* the current directory and run [`dotnet new classlib`](../tools/dotnet-new.md) to create the source project. Rename *Class1.cs* to *PrimeService.cs*. To use test-driven development (TDD), you create a failing implementation of the `PrimeService` class:

```csharp
using System;

namespace Prime.Services
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
throw new NotImplementedException("Please create a test first");
}
}
}
```

Change the directory back to the *unit-testing-using-nunit* directory. Run [`dotnet sln add PrimeService/PrimeService.csproj`](../tools/dotnet-sln.md) to add the class library project to the solution.

## Install the NUnit project template

The NUnit test project templates need to be installed before creating a test project. This only needs to be done once on each developer machine where you'll create new NUnit projects. Run [`dotnet new -i NUnit3.DotNetNew.Template`](../tools/dotnet-new.md) to install the NUnit templates.

```
dotnet new -i NUnit3.DotNetNew.Template
```

### Creating the test project

Next, create the *PrimeService.Tests* directory. The following outline shows the directory structure:

```
/unit-testing-using-nunit
unit-testing-using-nunit.sln
/PrimeService
Source Files
PrimeService.csproj
/PrimeService.Tests
```

Make the *PrimeService.Tests* directory the current directory and create a new project using [`dotnet new nunit`](../tools/dotnet-new.md). The dotnet new command creates a test project that uses NUnit as the test library. The generated template configures the test runner in the *PrimeServiceTests.csproj* file:

```xml
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="NUnit" Version="3.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
</ItemGroup>
```

The test project requires other packages to create and run unit tests. `dotnet new` in the previous step added the Microsoft test SDK, the NUnit test framework, and the NUnit test adapter. Now, add the `PrimeService` class library as another dependency to the project. Use the [`dotnet add reference`](../tools/dotnet-add-reference.md) command:

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

You can see the entire file in the [samples repository](https://github.com/dotnet/docs/blob/master/samples/core/getting-started/unit-testing-using-nunit/PrimeService.Tests/PrimeService.Tests.csproj) on GitHub.

The following outline shows the final solution layout:

```
/unit-testing-using-nunit
unit-testing-using-nunit.sln
/PrimeService
Source Files
PrimeService.csproj
/PrimeService.Tests
Test Source Files
PrimeServiceTests.csproj
```

Execute [`dotnet sln add .\PrimeService.Tests\PrimeService.Tests.csproj`](../tools/dotnet-sln.md) in the *unit-testing-using-dotnet-test* directory.

## Creating the first test

The TDD approach calls for writing one failing test, making it pass, then repeating the process. Remove *UnitTest1.cs* from the *PrimeService.Tests* directory and create a new C# file named *PrimeService_IsPrimeShould.cs* with the following content:

```csharp
using NUnit.Framework;
using Prime.Services;

namespace Prime.UnitTests.Services
{
[TestFixture]
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;

public PrimeService_IsPrimeShould()
{
_primeService = new PrimeService();
}

[Test]
public void ReturnFalseGivenValueOf1()
{
var result = _primeService.IsPrime(1);

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

The `[TestFixture]` attribute denotes a class that contains unit tests. The `[Test]` attribute indicates a method is a test method.

Save this file and execute [`dotnet test`](../tools/dotnet-test.md) to build the tests and the class library and then run the tests. The NUnit test runner contains the program entry point to run your tests. `dotnet test` starts the test runner using the unit test project you've created.

Your test fails. You haven't created the implementation yet. Make this test pass by writing the simplest code in the `PrimeService` class that works:

```csharp
public bool IsPrime(int candidate)
{
if (candidate == 1)
{
return false;
}
throw new NotImplementedException("Please create a test first");
}
```

In the *unit-testing-using-nunit* directory, run `dotnet test` again. The `dotnet test` command runs a build for the `PrimeService` project and then for the `PrimeService.Tests` project. After building both projects, it runs this single test. It passes.

## Adding more features

Now that you've made one test pass, it's time to write more. There are a few other simple cases for prime numbers: 0, -1. You could add new tests with the `[Test]` attribute, but that quickly becomes tedious. There are other NUnit attributes that enable you to write a suite of similar tests. A `[TestCase]` attribute is used to create a suite of tests that execute the same code but have different input arguments. You can use the `[TestCase]` attribute to specify values for those inputs.

Instead of creating new tests, apply this attribute to create a single data driven test. The data driven test is a method that tests several values less than two, which is the lowest prime number:

[!code-csharp[Sample_TestCode](../../../samples/core/getting-started/unit-testing-using-nunit/PrimeService.Tests/PrimeService_IsPrimeShould.cs?name=Sample_TestCode)]

Run `dotnet test`, and two of these tests fail. To make all of the tests pass, change the `if` clause at the beginning of the method:

```csharp
if (candidate < 2)
```

Continue to iterate by adding more tests, more theories, and more code in the main library. You have the [finished version of the tests](https://github.com/dotnet/docs/blob/master/samples/core/getting-started/unit-testing-using-nunit/PrimeService.Tests/PrimeService_IsPrimeShould.cs) and the [complete implementation of the library](https://github.com/dotnet/docs/blob/master/samples/core/getting-started/unit-testing-using-nunit/PrimeService/PrimeService.cs).
You've built a small library and a set of unit tests for that library. You've structured the solution so that adding new packages and tests is part of the normal workflow. You've concentrated most of your time and effort on solving the goals of the application.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="nunit" Version="3.9.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PrimeService\PrimeService.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using NUnit.Framework;
using Prime.Services;

namespace Prime.UnitTests.Services
{
[TestFixture]
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;

public PrimeService_IsPrimeShould()
{
_primeService = new PrimeService();
}

[Test]
public void ReturnFalseGivenValueOf1()
{
var result = _primeService.IsPrime(1);

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

#region Sample_TestCode
[TestCase(-1)]
[TestCase(0)]
[TestCase(1)]
public void ReturnFalseGivenValuesLessThan2(int value)
{
var result = _primeService.IsPrime(value);

Assert.IsFalse(result, $"{value} should not be prime");
}
#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Prime.Services
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
if (candidate < 2)
{
return false;
}
throw new NotImplementedException("Please create a test first");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

</Project>
22 changes: 22 additions & 0 deletions samples/core/getting-started/unit-testing-using-nunit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Unit testing using NUnit sample

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

## Key features

This sample demonstrates creating a library and writing effective unit tests that validate the features in that library. The example provides a service that indicates whether a number is prime.

## Restore and test

To run the tests, navigate to the *PrimeService.Tests* directory and type the following commands:

```
dotnet restore
dotnet test
```

`dotnet restore` restores the packages of both projects.
`dotnet test` builds both projects and runs all of the configured tests.

[!INCLUDE[DotNet Restore Note](~/includes/dotnet-restore-note.md)]

Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.10
MinimumVisualStudioVersion = 15.0.26124.0
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrimeService", "PrimeService\PrimeService.csproj", "{A14B23C8-8407-4D0F-BD61-51158C294C25}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrimeService.Tests", "PrimeService.Tests\PrimeService.Tests.csproj", "{ABD4B561-111A-40DE-8703-50E416B24748}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Debug|x64.ActiveCfg = Debug|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Debug|x64.Build.0 = Debug|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Debug|x86.ActiveCfg = Debug|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Debug|x86.Build.0 = Debug|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Release|Any CPU.Build.0 = Release|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Release|x64.ActiveCfg = Release|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Release|x64.Build.0 = Release|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Release|x86.ActiveCfg = Release|Any CPU
{A14B23C8-8407-4D0F-BD61-51158C294C25}.Release|x86.Build.0 = Release|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Debug|x64.ActiveCfg = Debug|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Debug|x64.Build.0 = Debug|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Debug|x86.ActiveCfg = Debug|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Debug|x86.Build.0 = Debug|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Release|Any CPU.Build.0 = Release|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Release|x64.ActiveCfg = Release|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Release|x64.Build.0 = Release|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Release|x86.ActiveCfg = Release|Any CPU
{ABD4B561-111A-40DE-8703-50E416B24748}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5E9E068D-AA46-4AC6-ADD1-0046FB77059C}
EndGlobalSection
EndGlobal

0 comments on commit 311c92d

Please sign in to comment.