Introduction to Unit Testing on .Net Core with xUnit and the CLI

Unit testing is a common practice in software development which involves breaking pieces of code down into small "units" which can be individually tested in isolation against their expected behavior for given scenarios.

This post is intended to be a brief tutorial of how to create and integrate unit tests into your .net core projects however if you'd like to read more about what unit tests are and how they can benefit your codebase you can read more information here and a good discussion titled Is Unit Testing Worth The Effort.

Creating a Unit Test Project

The .Net CLI makes it easy to create a new unit test project with a choice of the xUnit or MsTest test frameworks, for this demo we shall be using xUnit.

Use the dotnet new command to create a new xunit test project and open it in VsCode.

dotnet new xunit --name MyTestProject  
cd MyTestProject  
code .  
Writing a first Unit Test

Our new project file should contain a class file called UnitTest1.cs where we will write our test. In a nutshell, a test must should compare the output of a function (or some lines of code) with a expected value using the Assert library that's included as part of the xUnit library.

In this example we'll assert that 2 x 5 is equal to 10.

using System;  
using Xunit;

namespace MyTestProject  
{
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            var expected = 10;
            var actual = 2 * 5;

            Assert.Equal(expected, actual);
        }
    }
}
Running Unit Tests with the CLI

To run unit tests the CLI contains a test command that will run our tests and give us some feedback.

dotnet test

[xUnit.net 00:00:02.1934262]   Discovering: MyTestProject
[xUnit.net 00:00:02.6135422]   Discovered:  MyTestProject
[xUnit.net 00:00:02.7951588]   Starting:    MyTestProject
[xUnit.net 00:00:03.3670330]   Finished:    MyTestProject

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.  
Test Run Successful.  

Take note of the first execution step - Discovering Tests. Tests are generally identified as void methods in our test project that have been decorated with the Fact (or Theory) property.

If a test fails, the test runner will provide some feedback on where the test failed. In this example I've changed the expected variable to be 11 instead of 10 to make the test fail.

Failed   MyTestProject.UnitTest1.Test1  
Error Message:  
 Assert.Equal() Failure
Expected: 11  
Actual:   10  
Stack Trace:  
   at MyTestProject.UnitTest1.Test1() in /home/Source/MyTestProject/UnitTest1.cs:line 1
4  
Test Run Failed.

Total tests: 1. Passed: 0. Failed: 1. Skipped: 0.  
Installing additional test libraries

While the xUnit framework on its own provides plenty of tools to create a test suite, you may want to include additional packages to improve productivity and readability of your tests. In this instance we'll add the FluentAssertions library to our project to enhance the readability of our test.

Install the nuget package to our project we need to use the dotnet add package command.

dotnet add MyTestProject.csproj package FluentAssertions  

With the addition of this package, we should now be able to access the library's Should extension methods instead of using xUnit's Assert method.

using System;  
using Xunit;  
using FluentAssertions;

namespace MyTestProject  
{
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {
            var expected = 11;
            var actual = 2 * 5;

            actual.Should().Be(expected);
        }
    }
}
Debugging Unit Tests with VsCode

Debugging tests is now very easy with VsCode, just set a breakpoint and click the text "Debug Test" which should appear above the method name and VsCode should handle the rest.

Fig 1: Click debug test to launch the debugger
Fig 2: Debugging a test

Other command line features

If you're using a test suite consisting of multiple projects, you can use the list function to output a list of all the tests in a single project.

dotnet test MyTestProject.csproj -t

The following Tests are available:  
[xUnit.net 00:00:01.9573981]   Discovering: MyTestProject
[xUnit.net 00:00:02.3525320]   Discovered:  MyTestProject
    MyTestProject.UnitTest1.Test1
    MyTestProject.UnitTest1.Test2
    MyTestProject.UnitTest1.Test3

You can target a specific test/group of tests using the filter property.

// Finds all tests with the text Test3 in
dotnet test MyTestProject.csproj --filter DisplayName~Test3

// Run test 1 only
dotnet test MyTestProject.csproj --filter DisplayName=MyTestProject.UnitTest1.Test1

// Run all tests apart from test 1
dotnet test MyTestProject.csproj --filter DisplayName!=MyTestProject.UnitTest1.Test1
Adding a test project to an existing solution

We've covered a brief overview of how to create and run some tests but how can we integrate a unit test project with an existing code library? Here is a short example using the CLI.

// create solution file called NameGenerator
mkdir NameGenerator  
dotnet new sln

// create project for business logic
mkdir NameGenerator.Business  
cd NameGenerator.Business  
dotnet new classlib  
cd ..

// create project for tests
mkdir NameGenerator.Tests  
cd NameGenerator.Tests  
dotnet new xunit  
cd ..

dotnet sln add NameGenerator.Business/NameGenerator.Business.csproj  
dotnet sln add NameGenerator.Tests/NameGenerator.tests.csproj  
dotnet add package FluentAssertions

// Add a reference to our Business Logic code to our test project
dotnet add reference ../NameGenerator.Business/NameGenerator.Business.csproj

code .  

We can add some simple code to our Business Logic project.

using System;

namespace NameGenerator.Business  
{
    public class NameGenerator
    {
        public string GenerateName(string forename, string surname)
        {
            return $"{forename} {surname}";
        }
    }
}

We should then add the following code to our test project to verify our functionality works as expected.

using System;  
using Xunit;

using FluentAssertions;  
using NameGenerator.Business;

namespace NameGenerator.Tests  
{
    public class NameGeneratorTests
    {
        [Fact]
        public void Test1()
        {
            var sut = new NameGenerator.Business.NameGenerator();
            var expected = "Joe Bloggs";

            sut.GenerateName("Joe", "Bloggs")
                .Should()
                .Be(expected);
        }
    }
}

Now we should be able to run our test against the business logic code with dotnet test.

I hope that through these examples you can get up and running with writing and integrating unit tests into your .Net Core projects using the CLI.

Using the .Net Core CLI to Organise Projects and Solutions

When starting out building applications with .Net Core, it's very easy to spin up a new project using "dotnet new" and start writing code however when it comes to creating more complex solutions spanning multiple projects.

Unfortunately Visual Studio Code and other cross platform editors don't provide as much help with this as the full version of Visual Studio on PC. Thankfully the .Net Core SDK comes loaded with a command line interface (CLI) that provides functionality for most of the common actions which are.

Create new solution
// uses current dir name
dotnet new sln

// specify a solution name
dotnet new sln --name mysolution  
Create new project
dotnet new [type]  
dotnet new [type] --name myproject

project types: web, mvc, webapi, classlib, mstest, xunit, webconfig  
Manage projects in solution
dotnet sln mysolution.sln add path/myproject.csproj  
dotnet sln mysolution.sln add path1/proj1.csproj path2/proj2.csproj

dotnet sln mysolution.sln remove path/myproject.csproj  
dotnet sln mysolution.sln remove path1/proj1.csproj path2/proj2.csproj

// shows all projects in solution
dotnet sln mysolution.sln list  
Manage nuget packages in a project
dotnet add package packagename  
dotnet add myproj.csproj package packagname

dotnet remove package packagename  
dotnet remove myproj.csproj package packagename  
Manage references in a project
dotnet add reference path/myproject.csproj  
dotnet add myproject.csproj reference path/myref.csproj

dotnet remove reference path/myproject.csproj  
dotnet remove myproject.csproj reference path/myref.csproj

// list all references in csproj
dotnet list reference  
dotnet list myproject.csproj reference  
Build & run solutions
// commands
dotnet restore  
dotnet clean  
dotnet build  
dotnet run

// target specific project
dotnet [command] -p myproject/myproject.csproj

// build in release mode
dotnet [command] -c release  
Deploy a solution
dotnet pack  
dotnet pack path/myproj.csproj

//use release mode
dotnet pack -c release

// outputs myproj.1.0.0-Preview.nupkg
dotnet pack path/myproj.csproj --version-suffix Preview

dotnet publish  
dotnet publish -p myproj.csproj  
dotnet publish -c release  
Adding new classes/files

The .Net Core CLI doesn't provide functionality to create new class files yet however Omnisharp's C# extension for Visual Studio Code enables you to right click and create these files.

Hopefully some of you can find some value in this .Net CLI crash course and that it helps you familiarise yourself with the CLI in a short space of time.

Debugging C# Code with Visual Studio Code and Omnisharp

Visual Studio Code on its own is just a lightweight code editor however Omnisharp's C# extension includes debugging capabilities that makes VsCode a productive C# development environment.

Prerequisites

To write and debug C# applications on Linux the following prerequisites must be installed:

Enabling Debugging

When opening a new C# project for the first time in VsCode a popup window should display asking if you would like to add debug assets to your project - Select Yes when you see this message.

You should be able to see a new .vscode folder in your project which contains 2 files - tasks.json and launch.json.
The Tasks.json file should be populated with configuration data for the dotnet build task so that VsCode can build out project when we click the launch button.

{
    "version": "0.1.0",
    "command": "dotnet",
    "isShellCommand": true,
    "args": [],
    "tasks": [
        {
            "taskName": "build",
            "args": [
                "${workspaceRoot}/newconsole.csproj"
            ],
            "isBuildCommand": true,
            "problemMatcher": "$msCompile"
        }
    ]
}

The Launch.json file contains configuration data for the available debugging modes which by default are launch (from VsCode) and attach (to a running process).

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceRoot}/bin/Debug/netcoreapp1.1/newconsole.dll",
            "args": [],
            "cwd": "${workspaceRoot}",
            "console": "internalConsole",
            "stopAtEntry": false,
            "internalConsoleOptions": "openOnSessionStart"
        },
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}

Launching the Debugger from VsCode

Launching the debugger from VsCode is a very simple process for Console and Web projects, simply set a breakpoint in your code, navigate to the debug window (ctrl+shift+d) and hit the play button - the ".Net Core Launch" option should be selected by default. Your application should now stop at your breakpoints.

Attach to a process/website

Attaching the debugger to a running process is also very easy with VsCode, set your breakpoints, select the ".Net Core Attach" option from the debug menu and hit play. The task bar should show a list of running processes you can choose to attach your debugger to - in this example we shall attach to a running dotnet website process.

Exploring the Debug panes

The debug window in VsCode may seem heavily stripped down compared to the fully fledged version of Viual Studio however it provides enough functionality to cover the majority of use cases with the following panes:

  • Local Variables
  • Watch Window
  • Call Stack
  • Breakpoints

The local variable and watch windows provide essential variable tracking and modification functions while the watch window also enables the execution of methods on the fly including LINQ extension methods which is extremely useful.

The call stack window functions the same as its full fledged Visual Studio counterpart enabling crawling back up through the code execution heirarchy with full variable tracking.

Debuging on non-standard linux distros

If you've been following the older posts on this blog you will have noticed that I'm using VsCode on my Chromebook which is running a non-standard Liux Distribution based on Ubuntu 16.04 - GalliumOS. As of writing this article, Omnisharp executes its debugger assembly based on the identifier of the operating system running VsCode (in my case galliumos-2.1: an unrecognized operating system).

Luckily for us VsCode and all its extensions are written in Javascript meaning that we can get around this by editing a *.js file.

Find the location of your omnisharp extension on your machine and open the platform.js file. On my machine the path is:

/home/myusername/.vscode/extensions/ms-vscode.csharp-1.8.1/out/src/platform.js

In here there is a function called getRuntimeIdHelper which dictates what distribution to use. To get it to work with GalliumOS v2.1 I just had to add a new case block to the switch statement to handle GalliumOS and now C# debugging works with GalliumOS.

case 'galliumos':  
    return ubuntu_16_04;
    break;

I hope this method works for others building .net core apps using other non-standard Lunix distributions.

C# Development on Linux with .Net Core & Visual Studio Code

C# Development on Linux with .Net Core & Visual Studio Code

Framework and Prerequisites

Before we can start writing C# code on our machine, there are a few packages we need to install as prerequisites.

With these software packages installed you should be good to go. Your system is now ready to start writing, building and running C# code with any code editor. Although this guide is focused around using Visual Studio Code, please skip to the next section if you'd prefer to use a different code editor.

Setting up Visual Studio Code

Download the latest version of VsCode here and follow the installation instructions for your Linux distribution. If you are running a Debian/Ubuntu based Linux distro, download the *.deb installer and install VsCode with the dpkg command.

sudo dpkg -i <VsCodeFileName>.deb  

Once you've installed VsCode, open it up and install the C# extension by Omnisharp which will provide intellisense, autocomplete and other helpful notifications in your editor.

Creating and Running C# Projects

Creating a new .Net Core project is easy and can be done from the .Net Core command line interface using the "dotnet new" command followed by the type of project you want to create. For this example we will be creating a simple console app but you can find the documentation about the .Net Core CLI https://docs.microsoft.com/en-us/dotnet/articles/core/tools/.

To create a new project, first of all create a directory for the code to sit and then use the dotnet new command.

mkdir myconsoleapp  
cd myconsoleapp  
dotnet new console  

In order to build/run the project we need to download the project dependencies using the "restore" command, build it with the "build" command and run it with the "run" command.

dotnet restore  
dotnet build  
dotnet run  

When running the default C# console project, the program should display a simple "Hello World!" message.

We can dive in to VsCode and look at the code of our current working directory using the "code" command followed by a full stop (period).

code .  

The dotnet cli should've created a myconsoleapp.csproj project file and a Program.cs code file containing the following code.

using System;

namespace myconsoleapp  
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Hello World!");
        }
    }
}

In VsCode you should be able to edit the code, save the file then build and run it via the command line. You may even build and run the code inside VsCode using the integrated terminal (View > Integrated Terminal)

Installing Nuget Packages

An important aspect of .Net Development is being able to make use of third party tools and packages available via Nuget.

For those who have used earlier versions of the .Net Core framework this used to be easy as new projects used to contain a project.json file which has a list of all the Nuget Packages/Dependencies in a project which could be edited easily with full intellisense in VsCode.

Sadly this isn't the case now, following the version 1 release of .Net Core, the team decided to revert back to the old XML based *.csproj based files which are an absolute pig to edit manually in an editor.

Thankfully for us there is now a Nuget Package Manager extension available for VsCode that enables us to do so. Install this extension then you'll be able to install Nuget Packages into your .Net Core projects via the command pallet in VsCode and your project file will be updated automatically.

For this example let's add the popular DateTime package NodaTime to our project using the following commands from the VsCode command Pallette.

Nuget Package Manager: Add Package  
NodaTime  

Now we should be able to reference the NodaTime package with a using statement in our code and call the library with full intellisense (thanks Omnisharp!). I've added some NodaTime code to our previous example here.

using System;  
using NodaTime;

namespace myconsoleapp  
{
    class Program
    {
        static void Main(string[] args)
        {
            Instant now = SystemClock.Instance.GetCurrentInstant();
            Console.WriteLine($"Hello World!, the time is {now.ToString()}");
        }
    }
}

Now if we restore, build and run our app we should get our hello message with the current date from NodaTime.

Enjoy writing C# code with your editor of choice on Linux!

Follow up topics will include debugging and unit testing .Net Core applications on Linux.

Web Development on a Chromebook Part 2: Setting Up Development Tools

Web Development on a Chromebook Part 2: Setting Up Development Tools

Following on from part 1: Installing GalliumOS on a Chromebook - we should have full access to install applications and developer tools onto the Chromebook through GalliumOS (or any other Linux distribution). There are many tools and editors available for web development, in this tutorial we're going to setup a complete web development environment by installing NodeJS - for running server side Javascript and installing packages, Git - for source control, Visual Studio Code my preferred code editor and a couple of NPM packages to generate some skeleton web applications to get us up and running quickly.

Installing NodeJS

NodeJs can be installed via the command line using the standard sudo apt-get install command however with GalliumOS, I'd strongly advise installing node via the Node Version Manager (NVM). I found this easier because when Node is installed using sudo, all node commands need to be executed with sudo permissions however this falls over when automated scripts try to run node/npm commands without sudo permissions and it becomes difficult to maintain. Using the NVM instead enables you to run any node/npm command without using sudo and it also enables multiple versions of node to be installed and managed on the same machine with he ability to switch versions on demand which is pretty cool.

To install the Node Version Manager run the following command:

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash  

Once the NVM has been installed we can install the latest version of NodeJS

nvm install 6.10  

One installed, run the following command to double check that you have a version of NodeJs installed:

nvm ls  

Now node is installed, we just need to install Node's package manager (NPM) and we're ready to install VsCode

npm install -g  

Installing Visual Studio Code

To install Visual Studio Code we first need to get the installer from the VsCode Website (download the Debian *.deb installer and install it from the command line.

sudo dpkg -i <VsCodeFileName>.deb  

Now we're all setup, navigate to a directory on your file system and run the following command to launch VsCode

code .  

We've now turned our ChromeBook into a portable web development machine, stay tuned for more posts on how to be productive using visual studio code.