Dot Net Core In Memory Unit Testing Using xUnit

When I started using .Net Core and xUnit I found it difficult to find information on how to mock or fake the Entity Framework database code.  So I’m going to show a minimized code sample using xUnit, Entity Framework, In Memory Database with .Net Core.  I’m only going to setup two projects: DataSource and UnitTests.

The DataSource project contains the repository, domain and context objects necessary to connect to a database using Entity Framework.  Normally you would not unit test this project.  It is supposed to be set up as a group of pass-through objects and interfaces.  I’ll setup POCOs (Plain Old C# Object) and their entity mappings to show how to keep your code as clean as possible.  There should be no business logic in this entire project.  In your solution, you should create one or more business projects to contain the actual logic of your program.  These projects will contain the objects under unit test.

The UnitTest project specaks for itself.  It will contain the in memory Entity Framework fake code with some test data and a sample of two unit tests.  Why two tests?  Because it’s easy to create a demonstration with one unit test.  Two tests will be used to demonstrate how to ensure that your test data initializer doesn’t accidentally get called twice (causing twice as much data to be created).

The POCO

I’ve written about Entity Framework before and usually I’ll use data annotations, but POCOs are much cleaner.  If you look at some of my blog posts about NHibernate, you’ll see the POCO technique used.  The technique of using POCOs means that you’ll also need to setup a separate class of mappings for each table.  This keeps your code separated into logical parts.  For my sample, I’ll put the mappings into the Repository folder and call them TablenameConfig.  The mapping class will be a static class so that I can use the extension property to apply the mappings.  I’m getting ahead of myself so let’s start with the POCO:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal? Price { get; set; }
}

That’s it.  If you have the database defined, you can use a mapping or POCO generator to create this code and just paste each table into it’s only C# source file.  All the POCO objects are in the Domain folder (there’s only one and that’s the Product table POCO).

The Mappings

The mappings file looks like this:

using DataSource.Domain;
using Microsoft.EntityFrameworkCore;

namespace DataSource.Repository
{
    public static class ProductConfig
    {
        public static void AddProduct(this ModelBuilder modelBuilder, string schema)
        {
            modelBuilder.Entity<Product>(entity =>
            {
                entity.ToTable("Product", schema);

                entity.HasKey(p => p.Id);

                entity.Property(e => e.Name)
                    .HasColumnName("Name")
                    .IsRequired(false);

                entity.Property(e => e.Price)
                    .HasColumnName("Price")
                    .IsRequired(false);
            });
        }
    }
}

That is the whole file, so now you know what to include in your usings.  This class will be an extension method to a modelBuilder object.  Basically, it’s called like this:

modelBuilder.AddProduct("dbo");

I passed the schema as a parameter.  If you are only using the DBO schema, then you can just remove the parameter and force it to be DBO inside the ToTable() method.  You can and should expand your mappings to include relational integrity constraints.  The purpose in creating a mirror of your database constraints in Entity Framework is to give you a heads-up at compile-time if you are violating a constraint on the database when you write your LINQ queries.  In the “good ol’ days” when accessing a database from code meant you created a string to pass directly to MS SQL server (remember ADO?), you didn’t know if you would break a constraint until run time.  This makes it more difficult to test since you have to be aware of what constraints exist when you’re focused on creating your business code.  By creating each table as a POCO and a set of mappings, you can focus on creating your database code first.  Then when you are focused on your business code, you can ignore constraints, because they won’t ignore you!

The EF Context

Sometimes I start by writing my context first, then create all the POCOs and then the mappings.  Kind of a top-down approach.   In this example, I’m pretending that it’s done the other way around.  You can do it either way.  The context for this sample looks like this:

using DataSource.Domain;
using DataSource.Repository;
using Microsoft.EntityFrameworkCore;

namespace DataSource
{
    public class StoreAppContext : DbContext, IStoreAppContext
    {
        public StoreAppContext(DbContextOptions<StoreAppContext> options)
        : base(options)
        {

        }

        public DbSet<Product> Products { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.AddProduct("dbo");
        }
    }
}

You can see immediately how I put the mapping setup code inside the OnModelCreating() method.  As you add POCOs, you’ll need one of these for each table.  There is also an EF context interface defined, which is never actually used in my unit tests.  The purpose of the interface will be used in actual code in your program.  For instance, if you setup an API you’re going to end up using an IOC container to break dependencies.  In order to do that, you’ll need to reference the interface in your code and then you’ll need to define which object belongs to the interface in your container setup, like this:

services.AddScoped<IStoreAppContext>(provider => provider.GetService<StoreAppContext>());

If you haven’t used IOC containers before, you should know that the above code will add an entry to a dictionary of interfaces and objects for the application to use.  In this instance the entry for IStoreAppContext will match the object StoreAppContext.  So any object that references IStoreAppContext will end up getting an instance of the StoreAppContext object.  But, IOC containers is not what this blog post is about (I’ll create a blog post on that subject later).  So let’s move on to the unit tests, which is what this blog post is really about.

The Unit Tests

As I mentioned earlier, you’re not actually going to write unit tests against your database repository.  It’s redundant.  What you’re attempting to do is write a unit test covering a feature of your business logic and the database is getting in your way because your business object calls the database in order to make a decision.  What you need is a fake database in memory that contains the exact data you want your object to call so you can check and see if it make the correct decision.  You want to create unit tests for each tiny little decision made by your objects and methods and you want to be able to feed different sets of data to each tests or you can setup a large set of test data and use it for many tests.

Here’s the first unit test:

[Fact]
public void TestQueryAll()
{
    var temp = (from p in _storeAppContext.Products select p).ToList();

    Assert.Equal(2, temp.Count);
    Assert.Equal("Rice", temp[0].Name);
    Assert.Equal("Bread", temp[1].Name);
}

I’m using xUnit and this test just checks to see if there are two items in the product table, one named “Rice” and the other named “Bread”.  The _storeAppContext variable needs to be a valid Entity Framework context and it must be connected to an in memory database.  We don’t want to be changing a real database when we unit test.  The code for setting up the in-memory data looks like this:

var builder = new DbContextOptionsBuilder<StoreAppContext>()
    .UseInMemoryDatabase();
Context = new StoreAppContext(builder.Options);

Context.Products.Add(new Product
{
    Name = "Rice",
    Price = 5.99m
});
Context.Products.Add(new Product
{
    Name = "Bread",
    Price = 2.35m
});

Context.SaveChanges();

This is just a code snippet, I’ll show how it fits into your unit test class in a minute.  First, a DbContextOptionsBuilder object is built (builder).  This gets you an in memory database with the tables defined in the mappings of the StoreAppContext.  Next, you define the context that you’ll be using for your unit tests using the builder.options.  Once the context exists, then you can pretend you’re connected to a real database.  Just add items and save them.  I would create classes for each set of test data and put it in a directory in your unit tests (usually I call the directory TestData).

Now, you’re probably thinking: I can just call this code from each of my unit tests.  Which leads to the thought: I can just put this code in the unit test class initializer.  Which sounds good, however, the unit test runner will call your object each time it calls the test method and you end up adding to an existing database over and over.  So your first unit test executed will see two rows Product data, the second unit test will see four rows.  Go head and copy the above code into your constructor like this and see what happens.  You’ll see that TestQueryAll() will fail because there will be 4 records instead of the expected 2.  How do we make sure the initializer is executed only once for each test, but it must be performed on the first unit test call.  That’s where the IClassFixture comes in.  This is an interface that is used by xUnit and you basically add it to your unit test class like this:

public class StoreAppTests : IClassFixture<TestDataFixture>
{
    // unit test methods
}

Then you define your test fixture class like this:

using System;
using DataSource;
using DataSource.Domain;
using Microsoft.EntityFrameworkCore;

namespace UnitTests
{
    public class TestDataFixture : IDisposable
    {
        public StoreAppContext Context { get; set; }

        public TestDataFixture()
        {
            var builder = new DbContextOptionsBuilder<StoreAppContext>()
                .UseInMemoryDatabase();
            Context = new StoreAppContext(builder.Options);

            Context.Products.Add(new Product
            {
                Name = "Rice",
                Price = 5.99m
            });
            Context.Products.Add(new Product
            {
                Name = "Bread",
                Price = 2.35m
            });

            Context.SaveChanges();
        }

        public void Dispose()
        {

        }
    }
}

Next, you’ll need to add some code to the unit test class constructor that reads the context property and assigns it to an object property that can be used by your unit tests:

private readonly StoreAppContext _storeAppContext;

public StoreAppTests(TestDataFixture fixture)
{
    _storeAppContext = fixture.Context;
}

What happens is that xUnit will call the constructor of the TestDataFixture object one time.  This creates the context and assigns it to the fixture property.  Then the initializer for the unit test object will be called for each unit test.  This only copies the context property to the unit test object context property so that the unit test methods can reference it.  Now run your unit tests and you’ll see that the same data is available for each unit test.

One thing to keep in mind is that you’ll need to tear down and rebuild your data for each unit test if your unit test calls a method that inserts or updates your test data.  For that setup, you can use the test fixture to populate tables that are static lookup tables (not modified by any of your business logic).  Then create a data initializer and data destroyer that fills and clears tables that are modified by your unit tests.  The data initializer will be called inside the unit test object initializer and the destroyer will need to be called in an object disposer.

Where to Get the Code

You can get the complete source code from my GitHub account by clicking here.

 

Unit Testing with Moq

Introduction

There are a lot of articles on how to use Moq, but I’m going to bring out my die roller game example to show how to use Moq to roll a sequence of predetermined results.  I’m also going to do this using .Net Core.

The Setup

My sample program is a game.  The game is actually empty, because I want to show the minimal code to demonstrate Moq itself.  So let’s pretend there is a game object and it uses a die roll object to get a random outcome.  For those who have never programmed a game before, a die roll can be used to determine offense or defense of one battle unit attacking another in a turn-based board game.  However, unit tests must be repeatable and we must make sure we test as much code as possible (maximize our code coverage).

The sample project uses a Game object that is dependent on the DieRoller object.  To break dependencies, I required an instance of the DieRoller object to be fed into the Game object’s constructor:

public class Game
{
    private IDieRoller _dieRoller;

    public Game(IDieRoller dieRoller)
    {
        _dieRoller = dieRoller;
    }

    public int Play()
    {
        return _dieRoller.DieRoll();
    }
}

Now I can feed a Moq object into the Game object and control what the die roll will be.  For the game itself, I can use the actual DieRoller object by default:

public static void Main(string[] args)
{
    var game = new Game(new DieRoller());
}

An IOC container could be used as well, and I would highly recommend it for a real project.  I’ll skip the IOC container for this blog post.

The unit test can look something like this:

[Fact]
public void test_one_die_roll()
{
	var dieRoller = new Mock();
	dieRoller.Setup(x => x.DieRoll())
	.Returns(2);

	var game = new Game(dieRoller.Object);
	var result = game.Play();
	Assert.Equal(2, result);
}

I’m using xunit and moq in the above example.  So for my .Net Core project.json file:

{
	"version": "1.0.0-*",
	"testRunner": "xunit",
	"dependencies": {
		"DieRollerLibrary": "1.0.0-*",
		"GameLibrary": "1.0.0-*",
		"Microsoft.NETCore.App": {
			"type": "platform",
			"version": "1.0.1"
	},
	"Moq": "4.6.38-alpha",
	"xunit": "2.2.0-beta2-build3300",
	"xunit.core": "2.2.0-beta2-build3300",
	"dotnet-test-xunit": "2.2.0-preview2-build1029",
	"xunit.runner.visualstudio": "2.2.0-beta2-build1149"
},

"frameworks": {
	"netcoreapp1.0": {
		"imports": "dnxcore50"
		}
	}
}

 

Make sure you check the versions of these packages since they are constantly changing as of this blog post.  It’s probably best to use the NuGet package window or the console to get the latest version.

Breaking Dependencies

What does Moq do?  Moq is a quick and dirty way to create a fake object instance without writing a fake object.  Moq can take an interface or object definition and create a local instance with outputs that you can control.  In the XUnit sample above, Moq is told to return the number 2 when the DieRoll() method is called.  

Why mock an object?  As you create code, you’ll end up with objects that call other objectsThese cause dependencies.  In this example, the Game object is dependent on the DieRoller object:

 

Each object should have it’s own unit tests.  If we are testing two or more objects that are connected together, then technically, we’re performing an integration test.  To break dependencies, we need all objects not under test to be faked or mocked out.  If the Game object has multiple paths (using if/then, case statements for example) that depend on the roll of the die, then we’ll need to create unit tests where we can fix the die roll to a known set of values and execute the Game object to see the expected results.

First, I’m going to add a method to the Game class that will determine the outcome of an attack.  If the die roll is greater than 4, then the attack is successful (unit is hit).  If the die roll is 4 or less, then it’s a miss.  I’ll use true for a hit and false for a miss.  Here is my new Game class:

public class Game
{
    private IDieRoller _dieRoller;

	public Game(IDieRoller dieRoller)
	{
		_dieRoller = dieRoller;
	}

	public int Play()
	{
		return _dieRoller.DieRoll();
	}
	 
	public bool Attack()
	{
		if (_dieRoller.DieRoll() > 4)
		{
			return true;
		}
		
		return false;
	}
}


Now if we define a unit test like this:

[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(4)]
public void test_attack_unsuccessful(int dieResult)
{
	var dieRoller = new Mock();
	dieRoller.Setup(x => x.DieRoll())
	.Returns(dieResult);

	var game = new Game(dieRoller.Object);
	var result = game.Attack();
	Assert.False(result);
}


We can test all instances where the die roll should produce a false result.  To make sure we have full coverage, we’ll need to test the other two die results (where the die is a 5 or a 6):

[Theory]
[InlineData(5)]
[InlineData(6)]
public void test_attack_successful(int dieResult)
{
	var dieRoller = new Mock();
	dieRoller.Setup(x => x.DieRoll())
	.Returns(dieResult);

	var game = new Game(dieRoller.Object);
	var result = game.Attack();
	Assert.True(result);
}

Another Example

Now I’m going to make it complicated.  Sometimes in board games, we use two die rolls to determine an outcome.  First, I’m going to define an enum to allow three distinct results of an attack:

public enum AttackResult
{
	Miss,
	Destroyed,
	Damaged
}


Next, I’m going to create a new method named Attack2():

public AttackResult Attack2()
{
	if (_dieRoller.DieRoll() > 4)
	{
		if (_dieRoller.DieRoll() > 3)
		{
			return AttackResult.Damaged;
		}
		return AttackResult.Destroyed;
	}
	return AttackResult.Miss;
}


As you can see, the die could be rolled up to two times.  So, in order to test your results, you’ll need to fake two rolls before calling the game object.   I’m going to use the “theory” XUnit attribute to feed values that represent a damaged unit.  The values need to be the following:

5,4
5,5
5,6
6,4
6,5
6,6

Moq has a SetupSequence() method that allows us to stack predetermined results to return.  So every time the mock object is called, the next value will be returned.  Here’s the XUnit test to handle all die rolls that would result with an AttackReuslt of damaged:

[Theory]
[InlineData(5, 4)]
[InlineData(5, 5)]
[InlineData(5, 6)]
[InlineData(6, 4)]
[InlineData(6, 5)]
[InlineData(6, 6)]
public void test_attack_damaged(int dieResult1, int dieResult2)
{
	var dieRoller = new Mock();
	dieRoller.SetupSequence(x => x.DieRoll())
	.Returns(dieResult1)
	.Returns(dieResult2);

	var game = new Game(dieRoller.Object);
	var result = game.Attack2();
	Assert.Equal(AttackResult.Damaged, result);
}

Next, the unit testing for instances where the Attack2() method returns a AttackResult  of destroyed:

[Theory]
[InlineData(5, 1)]
[InlineData(5, 2)]
[InlineData(5, 3)]
[InlineData(6, 1)]
[InlineData(6, 2)]
[InlineData(6, 2)]
public void test_attack_destroyed(int dieResult1, int dieResult2)
{
	var dieRoller = new Mock();
	dieRoller.SetupSequence(x => x.DieRoll())
	.Returns(dieResult1)
	.Returns(dieResult2);

	var game = new Game(dieRoller.Object);
	var result = game.Attack2();
	Assert.Equal(AttackResult.Destroyed, result);
}

And finally, the instances where the AttackResult is a miss:

[Theory]
[InlineData(1, 1)]
[InlineData(2, 2)]
[InlineData(3, 3)]
[InlineData(4, 1)]
public void test_attack_miss(int dieResult1, int dieResult2)
{
	var dieRoller = new Mock();
	dieRoller.SetupSequence(x => x.DieRoll())
	.Returns(dieResult1)
	.Returns(dieResult2);

	var game = new Game(dieRoller.Object);
	var result = game.Attack2();
	Assert.Equal(AttackResult.Miss, result);
}

In the instance of the miss, the second die roll doesn’t really matter and technically, the unit test could be cut back to one input.  To test for every possible case, we could feed all six values into the second die.  Why would be do that?  Unit tests are performed for more than one reason.  Initially, they are created to prove our code as we write it.  Test-driven development is centered around this concept.  However, we also have to recognize that after the code is completed and deployed, the unit tests become regression tests.  These tests should live with the code for the life of the code.  The tests should also be incorporated into your continuous integration environment and executed every time code is checked into your version control system (technically, you should execute the tests every time you build, but your build times might be too long to do this).  This will prevent future code changes from accidentally breaking code that was already developed and tested.  In the Attack2() method a developer could enhance the code to use the second die roll when the first die roll is a 1,2,3 or 4.  The unit test above will not necessarily catch this change.  The only thing worse than a broken unit test is one that passes when it shouldn’t.

With that said, you should not have to perform an exhaustive test on every piece of code in your program.  I would only recommend such a tactic if the input data set was small enough to be reasonable.  For the example case above, the die size is 6 and the “Theory” attribute cuts the code you’ll need in order to perform multiple unit tests.  If you are using Microsoft Tests, then you can setup a loop that does the same function as the “Theory” attribute and test all iterations for one expected output in each unit test.


Where to get the Sample Code

You can download the sample code from my GitHub account by clicking here.