Testing 1,2,3 in asp.net core

Setting up testing in asp.net core 1.1 is not intuitive.  The tooling including the cli, has not yet caught up to the current version. In addition, a google search for mocking patterns (esp. entityframework) will lead astray.

  1. Check global.json for the solution folder.  Likely has two folders defined – src and test.  At least for now.  This global.json is likely to disappear from asp.net core in the near future (as of late 2016).
  2. Make sure all projects in solution directory are under one of  the global.json defined directories.  Do not confuse the solution folders in solution explorer (organization only) with the directories on disk, which is what globals.json refers.  The main projects will be in the “src” folder.  The test projects should be in the “test” folder.
  3.  Open the “test” directory in the command or powershell window.
  4. We are going to use the dotnet cli (command line interface) to create an xunit test project.  Currently Visual Studio does not create an asp.net core test project
  5. mkdir MyTestProject
  6. cd MyTestProject
  7. dotnet new -t xunittest
  8. dotnet restore
  9. “dotnet test” will run the test project from the command line and will run the default example test method.

This works fine if you want to “Assert.True(true);” which is what the sample test project will contain to start.  We probably want something more useful, such as testing one of the existing projects.  If that project, however, has been updated to dotnet 1.1, “adding a  reference” to that  project in the current XUnit setup will fail “incompatible versions”, since cli creates a asp.net core 1.0 test project.  Update the project.json.  This is what I have currently:

 

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable"
  },
  "dependencies": {
    "System.Runtime.Serialization.Primitives": "4.1.1",
    "xunit": "2.1.0",
    "dotnet-test-xunit": "2.2.0-preview2-build1029",
    "Microsoft.AspNetCore.TestHost": "1.1.0-*",
    "Microsoft.AspNetCore.Diagnostics": "1.1.0-*",
    "Microsoft.Extensions.Logging.Console": "1.1.0-*",
    "Microsoft.AspNetCore.Mvc": "1.1.0-*",
    "Microsoft.EntityFrameworkCore.InMemory": "1.1.0",
    "Moq": "4.6.38-alpha"
  },
  "testRunner": "xunit",
  "frameworks": {
    "netcoreapp1.1": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.1.0"
        }
      },
      "imports": [
        "dotnet5.4",
        "portable-net451+win8"
      ]
    }
  }
}

 

The next problem I ran into, was how to test a repository that is instantiated with a reference to a DBContext.  I first landed here, and spent more than an hour trying to get this work in asp.net core.  This turned out to be a wild goose chase.  I instead found a way to test with lightweight in memory objects.  The example below uses a DbContext that defines a DbSet of Groups (these are defined in the main project).  It also uses a User Repository based on ApplicationUser.  I have a custom method (FindDictionary) that returns a dictionary of the users.  The return is mocked in the example.

 

 

using Microsoft.EntityFrameworkCore;
using Moq;
using System.Collections.Generic;
using Xunit;

public class GroupRepositoryTests
 
 
{
   DbContextOptions<MyDbContext> _appOptions;
   Mock<IUserRepository> _userRepository;
 
 
    public GroupRepositoryTests()
    {
 
         _appOptions = new DbContextOptionsBuilder<MyDbContext>()
            .UseInMemoryDatabase(databaseName: "MyApi")
            .Options;
 
       _userRepository = new Mock<IUserRepository>();
 
        _userRepository.Setup(x => x.FindDictionary(It.IsAny<string[]>()))
            .Returns(new Dictionary<string, User> {
            { "joe@msn.com", new User { 
                 UserName = "joe@msn.com",
                 FirstName = "joe",
                 LastName = "shmoe"} }
        });
     }
 
    [Fact]
    public async void ShouldCreate() {
 
        using (var appContext = new MyDbContext(_appOptions)) {
 
            appContext.Add(new Group {
                 Name = "Group1",
                 Description = "An example group",
                 OwnerId = "joe@msn.com" });
            appContext.SaveChanges();
 
            var g = new GroupRepository(appContext, _userRepository.Object);
 
            var a = await g.GetAsync();
 
            Assert.True(a.Success);
 
       }
 
    }
}

 

Seemingly simple implementations (e.g. setting up testing for a repository) can eat up a good part of a day;  and that’s before any meaningful tests are written.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.