A few years ago, MS released .NET Core, then it released .NET Standard. I have avoided them and kept using .NET Framework to keep out of trouble.
I made a simple library and wondered what kind of project I should use and what ramifications of my selection are. And I ran into a trouble…. I didn’t really understand what is going on.
There are many .NET frameworks, the most common ones are
- .NET Framework – monolithic framework, basically a set of libraries we all know and love, including WPF, ASP.NET and so on.
- .NET Core – a fork of .NET framework reworked to be more modular.
There are several others (Compact, Xamarin, Mono…) and basically all of them somehow implement .NET. Your library used to target one of those and relied on (slightly) incompatible API.
So MS tried to make it easier to develop applications that can target multiple platforms = applications that can run on multiple platforms (e.g. Mono and .NET Framework) and created Portable Class Library profiles, where you say which platforms you want to target and as a result get a list of API that is on all platforms of the profile.
That went ok for a while, but it had problems, I won’t go into detail (see this lengthy blog: Introducing .NET Standard).
So the MS has decided that it will create an API specification, libraries will be written against this specification and then the libraries will be run on a platform that implements the standard.
Basically .NET Standard is an interface and each platform is an implementor (see Developer Metaphor for .NET Standard).
Ok, so far so good. We have .NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6 and 2.0. The .NET Core platform implements them and so does .NET Framework platform 4 and something.
While this was going on, MS has done some other things, e.g. first it got rid of .csproj project file and went with project.json, a few months later it replaced project.json with significantly simplified .csproj again (to keep the build toolchian same for all things, e.g. WPF applications and so on). It seems that MSBuild is too entrenched and MS wants a unified build chains, instead of two build chains.
Library project = .NET Standard
So now when you develop a library, you can develop against .NET Core, .NET Framework or you can choose to develop against .NET Standard. Obviously, I chose .NET Standard to have biggest audience and least hassle with different platforms.
If I need something that is missing from .NET Standard, I will just use NuGet.
I chose xUnit.Net for my unit framework and got to work. There is a nice tutorial over xUnit.net: Getting started with xUnit.net (.NET Core / ASP.NET Core).
You might note that there is
- Getting Started with xUnit.net (desktop)
- Getting started with xUnit.net (.NET Core / ASP.NET Core)
- Getting started with Devices
but no getting started with .NET Standard. The reason is kind of obvious, because the test runner needs to know the actual platform it will run tests against. See a comment of xUnit BDFL. If you want, you can easily run xUnit against multiple targets (=platforms) to make sure there are no kinks anywhere.
With an introduction of .NET Core platform, MS has added a CLI tool for common tasks. The program itself is called dotnet.exe. It is basically a CLI tool to create, scaffold, build, pack or test .NET Core projects.
This tool is only for .NET Core platform, not for .NET Framework or others.
By using dotnet.exe, you can easily do common tasks, such as:
C:\Users\jahav\source\repos>mkdir app C:\Users\jahav\source\repos>cd app C:\Users\jahav\source\repos\app>dotnet new sln --name myapp The template "Solution File" was created successfully. C:\Users\jahav\source\repos\app>dotnet new xunit --name mytest The template "xUnit Test Project" was created successfully. Processing post-creation actions... Running 'dotnet restore' on mytest\mytest.csproj... Restoring packages for C:\Users\jahav\source\repos\app\mytest\mytest.csproj... Generating MSBuild file C:\Users\jahav\source\repos\app\mytest\obj\mytest.csproj.nuget.g.props. Generating MSBuild file C:\Users\jahav\source\repos\app\mytest\obj\mytest.csproj.nuget.g.targets. Restore completed in 1,11 sec for C:\Users\jahav\source\repos\app\mytest\mytest.csproj. Restore succeeded. C:\Users\jahav\source\repos\app>dotnet sln add mytest\mytest.csproj Project `mytest\mytest.csproj` added to the solution. C:\Users\jahav\source\repos\app>dotnet test Build started, please wait... Build completed. Test run for C:\Users\jahav\source\repos\app\mytest\bin\Debug\netcoreapp2.0\mytest.dll(.NETCoreApp,Version=v2.0) Microsoft (R) Test Execution Command Line Tool verze 15.3.0-preview-20170628-02 Copyright (c) Microsoft Corporation. Všechna práva vyhrazena. Test are starting to run, please wait... [xUnit.net 00:00:00.4928198] Discovering: mytest [xUnit.net 00:00:00.5726261] Discovered: mytest [xUnit.net 00:00:00.6093754] Starting: mytest [xUnit.net 00:00:00.7880631] Finished: mytest Tests total: 1. Success: 1. Fail: 0. Ignored: 0 Test run was successful. Time of test run: 1,7359 sec
dotnet is also quite extensible, e.g. xunit is adding its own runner (dotnet xunit) that has some nicer features that standard dotnet test. ‘dotnet test’ vs. ‘dotnet xunit’
Let’s look at xunit .csproj:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" /> <PackageReference Include="xunit" Version="2.2.0" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" /> </ItemGroup> </Project>
- TargetFramework: netcoreapp2.0 – Platform the test cases will be run against. There can be multiple platforms specified (remember to change TargetFramework to TargetFrameworks)
Microsoft.NET.Test.Sdkpackage – will turn the project from a class library to a console application when building for .net core so that all assets needed to “run” are generated. This package does a lot of things. This package is needed, if you are using dotnet test. This is used for all testing frameworks (MSTest, xUnit, NUnit…)
xunit– package to add annotations to tests in the assembly. Doesn’t do anything really useful, it is mostly metadata.
xunit.runner.visualstudio– this is the xUnit test runner, that connects the xUnit with the .NET Core test runnign platform. Thanks to this, you can discover and run tests in visual studio or by using dotnet test.
In the xUnit tutorial is slightly different csproj.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="xunit" Version="2.3.1" /> <DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" /> </ItemGroup> </Project>
This csproj is missing
Microsoft.NET.Test.Sdk, so it’s not possible to use
dotnet test, but it uses a dotnet extension point:
DotNetCliToolReference . By adding this nuget (yes, really nuget package that is automatically downloaded for the project, no need to install separately) package to the project, you can use
BTW you can’t use xunit.console.x86.exe for .NET Core projects, that runner is for .NET Framework only.