Getting started: .NET Core with command line (2024)

Using .NET Core with the .NET SDK command line

In this article, we will demonstrate getting started with xUnit.net and .NET Core (including .NET 5), showing you how to write and run your first set of unit tests.

  • Download the .NET SDK
  • Create the unit test project
  • Write your first tests
  • Write your first theory
  • Running tests against multiple target frameworks
  • Run tests with Visual Studio

Note: The examples were done with xUnit.net v2 2.4.1, .NET SDK 5.0.102, and .NET 5.0. The version numbers, paths, and generated templates may differ for you, depending on which version you're using. Note that .NET Core 1.x-3.x and .NET 5.0+ are supported.

Download the .NET SDK

As of this writing, the .NET SDK is available for download for Windows, Linux, and macOS. Once you've downloaded and installed the SDK, open a fresh command prompt of your choice (CMD, PowerShell, Bash, etc.) and make sure that you can access the CLI by typing dotnet --version. You should be rewarded with a single line, describing the version of the .NET Core SDK you have installed:

$ dotnet --version5.0.102

Note: the first time you run the dotnet command, it may perform some post-installation steps. Once these one-time actions are done, it will execute your command.

Create the unit test project

From the command line, create a folder for your test project, change into it, and then create the project using dotnet new:

$ mkdir MyFirstUnitTests$ cd MyFirstUnitTests$ dotnet new xunitThe template "xUnit Test Project" was created successfully.Processing post-creation actions...Running 'dotnet restore' on ~/dev/MyFirstUnitTests/MyFirstUnitTests.csproj... Determining projects to restore... Restored ~/dev/MyFirstUnitTests/MyFirstUnitTests.csproj (in 217 ms).Restore succeeded.

If you look at the generated MyFirstUnitTests.csproj project file, you should see content that looks something like this:

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="coverlet.collector" Version="1.3.0"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> </ItemGroup></Project>

Let's quickly review what's in this project file:

  • TargetFramework specifies the target framework for your test project. By default this will be the latest version of .NET Core that your system supports (in this example, .NET 5.0). Later in this article, we will discuss running tests against multiple target frameworks.
  • IsPackable is here, though it is redundant (unit test projects cannot be packed by default). You can safely remove this line if you wish.
  • The xunit package brings in three child packages which include functionality that most developers want: xunit.core (the testing framework itself), xunit.assert (the library which contains the Assert class), and xunit.analyzers (which enables Roslyn analyzers to detect common issues with unit tests and xUnit.net extensibility).
  • The packages xunit.runner.visualstudio and Microsoft.NET.Test.Sdk are required for being able to run your test project inside Visual Studio as well as with dotnet test.
  • The coverlet.collector package allows collecting code coverage. If you don't intend to collect code coverage, you should remove this package reference.

A single empty unit test was also generated into UnitTest1.cs:

using System;using Xunit;namespace MyFirstUnitTests{ public class UnitTest1 { [Fact] public void Test1() { } }}

Now let's verify that everything is working:

$ dotnet test Determining projects to restore... All projects are up-to-date for restore. MyFirstUnitTests -> ~/dev/MyFirstUnitTests/bin/Debug/net5.0/MyFirstUnitTests.dllTest run for ~/dev/MyFirstUnitTests/bin/Debug/net5.0/MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)Microsoft (R) Test Execution Command Line Tool Version 16.8.3Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...A total of 1 test files matched the specified pattern.Passed! - Failed: 0, Passed: 1, Skipped: 0, Total: 1, Duration: 1 ms - MyFirstUnitTests.dll (net5.0)

Excellent! Let's go replace that empty unit test with our first real tests.

Write your first tests

Using your favorite text editor, open the UnitTest1.cs file and add a couple tests:

using Xunit;namespace MyFirstUnitTests{ public class UnitTest1 { [Fact] public void PassingTest() { Assert.Equal(4, Add(2, 2)); } [Fact] public void FailingTest() { Assert.Equal(5, Add(2, 2)); } int Add(int x, int y) { return x + y; } }}

Now let's go run the tests again and see what happens:

$ dotnet test Determining projects to restore... All projects are up-to-date for restore. MyFirstUnitTests -> ~/dev/MyFirstUnitTests/bin/Debug/net5.0/MyFirstUnitTests.dllTest run for ~/dev/MyFirstUnitTests/bin/Debug/net5.0/MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)Microsoft (R) Test Execution Command Line Tool Version 16.8.3Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...A total of 1 test files matched the specified pattern.[xUnit.net 00:00:00.33] MyFirstUnitTests.UnitTest1.FailingTest [FAIL] Failed MyFirstUnitTests.UnitTest1.FailingTest [1 ms] Error Message: Assert.Equal() FailureExpected: 5Actual: 4 Stack Trace: at MyFirstUnitTests.UnitTest1.FailingTest() in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 16Failed! - Failed: 1, Passed: 1, Skipped: 0, Total: 2, Duration: 4 ms - MyFirstUnitTests.dll (net5.0)

Now that we've gotten your first unit tests to run, let's introduce one more way to write tests: using theories.

Write your first theory

You may have wondered why your first unit tests use an attribute named [Fact] rather than one with a more traditional name like Test. xUnit.net includes support for two different major types of unit tests: facts and theories. When describing the difference between facts and theories, we like to say:

Facts are tests which are always true. They test invariant conditions.

Theories are tests which are only true for a particular set of data.

A good example of this is testing numeric algorithms. Let's say you want to test an algorithm which determines whether a number is odd or not. If you're writing the positive-side tests (odd numbers), then feeding even numbers into the test would cause it fail, and not because the test or algorithm is wrong.

Let's add a theory to our existing facts (including a bit of bad data, so we can see it fail):

[Theory][InlineData(3)][InlineData(5)][InlineData(6)]public void MyFirstTheory(int value){ Assert.True(IsOdd(value));}bool IsOdd(int value){ return value % 2 == 1;}

This time when we run our tests, we see a second failure, for our theory that was given 6:

Microsoft (R) Test Execution Command Line Tool Version 16.8.3Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...A total of 1 test files matched the specified pattern.[xUnit.net 00:00:00.35] MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [FAIL][xUnit.net 00:00:00.35] MyFirstUnitTests.UnitTest1.FailingTest [FAIL] Failed MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [1 ms] Error Message: Assert.True() FailureExpected: TrueActual: False Stack Trace: at MyFirstUnitTests.UnitTest1.MyFirstTheory(Int32 value) in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 30 Failed MyFirstUnitTests.UnitTest1.FailingTest [< 1 ms] Error Message: Assert.Equal() FailureExpected: 5Actual: 4 Stack Trace: at MyFirstUnitTests.UnitTest1.FailingTest() in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 16Failed! - Failed: 2, Passed: 3, Skipped: 0, Total: 5, Duration: 4 ms - MyFirstUnitTests.dll (net5.0)

Although we've only written 3 test methods, the test runner actually ran 5 tests; that's because each theory with its data set is a separate test. Note also that the runner tells you exactly which set of data failed, because it includes the parameter values in the name of the test.

Running tests against multiple target frameworks

Sometimes, you want to write tests and ensure they run against several target application platforms. The xUnit.net test runner that we've been using supports .NET Core 1.0 or later, .NET 5.0 or later, and .NET Framework 4.5.2 or later. With a single test project, we can have our tests run against multiple target frameworks. Open the .csproj file and make the following change.

Change TargetFramework:

<PropertyGroup> <TargetFramework>net5.0</TargetFramework></PropertyGroup>

To TargetFrameworks:

<PropertyGroup> <TargetFrameworks>net48;net5.0</TargetFrameworks></PropertyGroup>

dotnet test supports any combination of .NET Core (including .NET 5+) and .NET Framework targets. You can even include multiple versions of the same target framework (for example, it's legal to have something like <TargetFrameworks>net452;net461;net48;netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>). Application authors will typically only use a single target framework, related to the target framework the application is intended to run on. Library authors are more likely to use several target frameworks, to ensure their tests run successfully on all supported target frameworks.

dotnet test with xUnit.net does not currently support .NET Framework on non-Windows environments (like Linux and macOS). You can run .NET Framework tests in these environments using xunit.console.exe, as discussed in Getting Started with xUnit.net Using .NET Framework with the command line.

Related content: Why doesn't xUnit.net support netstandard?

Now when we run the tests, you can see that it runs both target frameworks, one after another:

$ dotnet test Determining projects to restore... Restored ~/dev/MyFirstUnitTests/MyFirstUnitTests.csproj (in 238 ms). MyFirstUnitTests -> ~/dev/MyFirstUnitTests/bin/Debug/net48/MyFirstUnitTests.dll MyFirstUnitTests -> ~/dev/MyFirstUnitTests/bin/Debug/net5.0/MyFirstUnitTests.dllTest run for ~/dev/MyFirstUnitTests/bin/Debug/net48/MyFirstUnitTests.dll (.NETFramework,Version=v4.8)Microsoft (R) Test Execution Command Line Tool Version 16.8.3Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...A total of 1 test files matched the specified pattern.[xUnit.net 00:00:00.31] MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [FAIL][xUnit.net 00:00:00.32] MyFirstUnitTests.UnitTest1.FailingTest [FAIL] Failed MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [2 ms] Error Message: Assert.True() FailureExpected: TrueActual: False Stack Trace: at MyFirstUnitTests.UnitTest1.MyFirstTheory(Int32 value) in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 30 Failed MyFirstUnitTests.UnitTest1.FailingTest [3 ms] Error Message: Assert.Equal() FailureExpected: 5Actual: 4 Stack Trace: at MyFirstUnitTests.UnitTest1.FailingTest() in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 16Failed! - Failed: 2, Passed: 3, Skipped: 0, Total: 5, Duration: 16 ms - MyFirstUnitTests.dll (net48)Test run for ~/dev/MyFirstUnitTests/bin/Debug/net5.0/MyFirstUnitTests.dll (.NETCoreApp,Version=v5.0)Microsoft (R) Test Execution Command Line Tool Version 16.8.3Copyright (c) Microsoft Corporation. All rights reserved.Starting test execution, please wait...A total of 1 test files matched the specified pattern.[xUnit.net 00:00:00.38] MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [FAIL][xUnit.net 00:00:00.38] MyFirstUnitTests.UnitTest1.FailingTest [FAIL] Failed MyFirstUnitTests.UnitTest1.MyFirstTheory(value: 6) [3 ms] Error Message: Assert.True() FailureExpected: TrueActual: False Stack Trace: at MyFirstUnitTests.UnitTest1.MyFirstTheory(Int32 value) in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 30 Failed MyFirstUnitTests.UnitTest1.FailingTest [< 1 ms] Error Message: Assert.Equal() FailureExpected: 5Actual: 4 Stack Trace: at MyFirstUnitTests.UnitTest1.FailingTest() in ~/dev/MyFirstUnitTests/UnitTest1.cs:line 16Failed! - Failed: 2, Passed: 3, Skipped: 0, Total: 5, Duration: 6 ms - MyFirstUnitTests.dll (net5.0)

Running tests with Visual Studio

If you're having problems discovering or running tests, you may be a victim of a corrupted runner cache inside Visual Studio. To clear this cache, shut down all instances of Visual Studio, then delete the folder %TEMP%\VisualStudioTestExplorerExtensions. Also make sure your solution is only linked against a single version of the Visual Studio runner NuGet package (xunit.runner.visualstudio).

If you have Visual Studio Community (or a paid-for version of Visual Studio), you can run your xUnit.net tests within Visual Studio's built-in test runner (named Test Explorer). Unfortunately, this does not include Express editions of Visual Studio (you should upgrade to the free Community Edition instead).

If your project doesn't have a solution file yet, you can use the dotnet command line to create one. Run the following two commands from your project folder:

$ dotnet new slnThe template "Solution File" was created successfully.$ dotnet sln add .Project `MyFirstUnitTests.csproj` added to the solution.

Now open your solution with Visual Studio. (The screen shots and menu items here are taken from Visual Studio 2019; your version may be slightly different.)

Make sure Test Explorer is visible (go to Test > Test Explorer). Depending on the version of Visual Studio you have, you may need to build your test assembly before tests are discovered. After a moment of discovery, you should see the list of discovered tests:

Getting started: .NET Core with command line (1)

Click the Run All link in the Test Explorer window, and you should see the results update in the Test Explorer window as the tests are run:

Getting started: .NET Core with command line (2)

You can click on a failed test to see the failure message, and the stack trace. You can click on the stack trace lines to take you directly to the failing line of code.

Copyright © .NET Foundation. Contributions welcomed at https://github.com/xunit/xunit/tree/gh-pages.
Getting started: .NET Core with command line (2024)

References

Top Articles
Latest Posts
Article information

Author: Laurine Ryan

Last Updated:

Views: 6329

Rating: 4.7 / 5 (77 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Laurine Ryan

Birthday: 1994-12-23

Address: Suite 751 871 Lissette Throughway, West Kittie, NH 41603

Phone: +2366831109631

Job: Sales Producer

Hobby: Creative writing, Motor sports, Do it yourself, Skateboarding, Coffee roasting, Calligraphy, Stand-up comedy

Introduction: My name is Laurine Ryan, I am a adorable, fair, graceful, spotless, gorgeous, homely, cooperative person who loves writing and wants to share my knowledge and understanding with you.