Building ASP.NET Core apps on CircleCI

Recently, my co-worker Willem pulled my attention to the .NET Microservices. Architecture for Containerized .NET Applications e-book. Although I have a strong background in Java and the Java platform, I started reading it, and soon I felt like trying it out. But building software without having automated builds and tests is not the real thing, so that was the first thing I wanted to do. I usually use CircleCI for that, but unfortunately they don’t seem to have an official guide for that.

Getting started

Earlier, I found out about that you can run a CircleCI build on your own machine, thanks to Docker. So I started by creating a .circleci/config.yml file with just the following contents:

version: 2
jobs:
  build:
    docker:
      - image: microsoft/aspnetcore-build:2.0
    steps:
      - checkout
      - run: find .

The e-book suggests to use the microsoft/aspnetcore-build:2.0 Docker image when building ASP.NET Core apps, so line 5 tells CircleCI to use that one. The build is a single step to see what our checkout looks like.

The first steps of building .NET Core applications is usually to restore the dependencies and tools of a project using dotnet restore. It is not needed in .NET Core 2.0 because it’s run implicitly by all commands that require a restore to occur, but it makes sense in continuous integration builds.

The second step is to actually build the source code; you can do this with dotnet build.

And finally, I would want to run some unit tests. The command for this is dotnet test.

Coding time

Time for some pieces of code! I followed the Getting started with .NET Core on macOS tutorial. The first thing is a C# class called Thing.cs in a module called SeedWork:

using System;

namespace Seedwork
{
    public class Thing
    {
        public string Get(int left, int right) => $"{left + right}";
    }
}

Then, since I want to make sure this piece of code works correctly, I add a module with tests called SeedWork.Test. This module has one C# class, ThingTest.cs:

using System;
using Xunit;

namespace Seedwork.Test
{
    public class ThingTest
    {
        [Fact]
        public void Test1()
        {
            Assert.Equal("42", new Thing().Get(19, 23));
        }
    }
}

Now, if I run the tests locally using dotnet test, the output is:

Build started, please wait...
Build started, please wait...
Build completed.

Test run for /Users/maarten/Projects/futbolin/Seedwork/bin/Debug/netstandard2.0/Seedwork.dll(.NETStandard,Version=v2.0)
Microsoft (R) Test Execution Command Line Tool Version 15.6.0-preview-20180109-01
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
System.IO.FileNotFoundException: No test is available in /Users/maarten/Projects/futbolin/Seedwork/bin/Debug/netstandard2.0/Seedwork.dll. Make sure test project has a nuget reference of package "Microsoft.NET.Test.Sdk" and framework version settings are appropriate and try again.
at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager.GetTestHostProcessStartInfo(IEnumerable`1 sources, IDictionary`2 environmentVariables, TestRunnerConnectionInfo connectionInfo)
at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyOperationManager.SetupChannel(IEnumerable`1 sources, CancellationToken cancellationToken)
at Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyExecutionManager.StartTestRun(TestRunCriteria testRunCriteria, ITestRunEventsHandler eventHandler)

Test Run Aborted.
Build completed.

Test run for /Users/maarten/Projects/futbolin/Seedwork.Test/bin/Debug/netcoreapp2.0/Seedwork.Test.dll(.NETCoreApp,Version=v2.0)
Microsoft (R) Test Execution Command Line Tool Version 15.6.0-preview-20180109-01
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
[xUnit.net 00:00:00.6259860]   Discovering: Seedwork.Test
[xUnit.net 00:00:00.6913870]   Discovered:  Seedwork.Test
[xUnit.net 00:00:00.6983110]   Starting:    Seedwork.Test
[xUnit.net 00:00:00.8797890]   Finished:    Seedwork.Test

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0.
Test Run Successful.
Test execution time: 2.2228 Seconds

It took me a while to figure what’s going on here: dotnet test tries to run tests in the Seedwork module first, but it fails. There are no tests in this module, but what is worse, there is no reference to the package “Microsoft.NET.Test.Sdk” package. Then it runs tests in the Seedwork.Test module, which succeeds, because it refers to that package and contains a test. This is easily fixed by specifying the project to test using dotnet test <PROJECT>.

Wrapping up

So I updated the .circleci/config.yml file to look like this:

version: 2
jobs:
  build:
    docker:
      - image: microsoft/aspnetcore-build:2.0
    steps:
      - checkout
      - run: find .
      - run: dotnet restore
      - run: dotnet build
      - run: dotnet test --no-build Seedwork.Test

Everything is pushed to Github and CircleCI happily builds my source code. Now on to more serious stuff…