Carl Rippon

Building SPAs

Carl Rippon
BlogBooks / CoursesAbout
This site uses cookies. Click here to find out more

Testing EF Core Repositories with xUnit and an In Memory Db

January 30, 2017
dotnet

I came across the EF Core In Memory database recently. It obviously won’t have all the features of a relational database but it might be useful when unit testing simple repository methods.

Let’s take it for a spin …

Starting point

We have the following repository that we want to test. We’re just going to test the Add method in this post:

public interface IPersonRepository
{
    ...
    ICollection<Person> GetAll();
    void Add(Person person);}
public class PersonRepository: IPersonRepository
{
    private PersonDataContext personDataContext;

    public PersonRepository(PersonDataContext personDataContext)
    {
        this.personDataContext = personDataContext;
    }

    ...

    public ICollection<Person> GetAll()
    {
        return personDataContext.People.ToList();
    }

    public Person Add(Person person)    {        personDataContext.People.Add(person);        personDataContext.SaveChanges();        return person;    }}

Here’s the EF data context and models behind our repository:

public class PersonDataContext: DbContext
{
    public PersonDataContext() { }
    public PersonDataContext(DbContextOptions<PersonDataContext> options): base(options) { }
    public DbSet<Person> People { get; set; }
    public DbSet<EmailAddress> EmailAddresses { get; set; }
}
public class Person
{
    public int PersonId { get; set; }
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public ICollection<EmailAddress> EmailAddresses { get; set; }
}
public class EmailAddress
{
    public int EmailAddressId { get; set; }
    public string Email { get; set; }
}

xUnit

So, let’s bring in xUnit by adding the following entries into

"dependencies": {
    ...
    "xunit": "2.2.0-beta5-build3474",
    "dotnet-test-xunit": "2.2.0-preview2-build1029"
},

We also need to tell Visual Studio that xUnit is going to be our test runner by setting the following as a root property in project.json as well:

"testRunner": "xunit"

Now we can start adding xUnit tests. Let’s just add a couple of simple tests to double check xUnit is wired up properly. Let’s add the following class containing a test that should pass and a test that should fail:

public class SimpleTest
{
    [Fact]
    public void PassingTest()
    {
        Assert.Equal(2, 2);
    }

    [Fact]
    public void FailingTest()
    {
        Assert.Equal(2, 3);
    }
}

If we open up Test Explorer you’ll see our tests and if you run them, 1 should pass and should 1 fail.

xunitVSTest

As a bonus, you can also run these tests from the command line by browsing to the app’s folder and running the following command:

dotnet test

Again, you should see 1 passing and 1 failing test.

In Memory Database

Before we test our repository, let’s bring in the In Memory database into our solution by adding the following dependency in

{
  "dependencies": {
    ...
    "Microsoft.EntityFrameworkCore.InMemory": "1.0.1"
  },
  ...
}

Repository Tests

So, let’s start testing our Add method in our repository by creating a class and a method to test the storyline when a person has no email address:

public class PersonRepositoryTests
{
    [Fact]
    public void Add_WhenHaveNoEmail()
    {
        IPersonRepository sut = GetInMemoryPersonRepository();
        Person person = new Person()
        {
            PersonId = 1,
            FirstName = "fred",
            Surname = "Blogs"
        };

        Person savedPerson = sut.Add(person);

        Assert.Equal(1, sut.GetAll().Count());
        Assert.Equal("fred", savedPerson.FirstName);
        Assert.Equal("Blogs", savedPerson.Surname);
        Assert.Null(savedPerson.EmailAddresses);
    }

    private IPersonRepository GetInMemoryPersonRepository()
    {
        DbContextOptions<PersonDataContext> options;
        var builder = new DbContextOptionsBuilder<PersonDataContext>();
        builder.UseInMemoryDatabase();
        options = builder.Options;
        PersonDataContext personDataContext = new PersonDataContext(options);
        personDataContext.Database.EnsureDeleted();
        personDataContext.Database.EnsureCreated();
        return new PersonRepository(personDataContext);
    }
}

GetInMemoryPersonRepository is a method that all our tests will use to spin up a PersonRepository containing no data. Line 26 tells our data context to use the In Memory database. Lines 29 and 30 ensures we have a new database with no data in it.

The test is straight forward. Lines 6-12 creates a repository and a person with no email address. Line 14 calls the Add method in our repository passing in the person. Lines 16-19 carry our checks.

If you run the tests, all should be good.

Now, let’s add a couple more tests to test adding a person with single and multiple email addresses:

[Fact]
public void Add_WhenHaveSingleEmail()
{
    IPersonRepository sut = GetInMemoryPersonRepository();
    Person person = new Person()
    {
        PersonId = 1,
        FirstName = "fred",
        Surname = "Blogs",
        EmailAddresses = new List<EmailAddress>()
        {
            new EmailAddress()
            {
                EmailAddressId = 1,
                Email = "fred.blogs@testmail.com"
            }
        }
    };

    Person savedPerson = sut.Add(person);

    Assert.Equal(1, sut.GetAll().Count());
    Assert.Equal("fred", savedPerson.FirstName);
    Assert.Equal("Blogs", savedPerson.Surname);
    Assert.Equal(1, savedPerson.EmailAddresses.Count());
    Assert.Equal("fred.blogs@testmail.com", savedPerson.EmailAddresses.ToList()[0].Email);
}

[Fact]
public void Add_WhenHaveMultipleEmail()
{
    IPersonRepository sut = GetInMemoryPersonRepository();
    Person person = new Person()
    {
        PersonId = 1,
        FirstName = "fred",
        Surname = "Blogs",
        EmailAddresses = new List<EmailAddress>()
        {
            new EmailAddress()
            {
                EmailAddressId = 1,
                Email = "fred.blogs@testmail.com"
            },
            new EmailAddress()
            {
                EmailAddressId = 2,
                Email = "fred.blogs@anothermail.com"
            }
        }
    };

    Person savedPerson = sut.Add(person);

    Assert.Equal(1, sut.GetAll().Count());
    Assert.Equal("fred", savedPerson.FirstName);
    Assert.Equal("Blogs", savedPerson.Surname);
    Assert.Equal(2, savedPerson.EmailAddresses.Count());
    Assert.Equal("fred.blogs@testmail.com", savedPerson.EmailAddresses.ToList()[0].Email);
    Assert.Equal("fred.blogs@anothermail.com", savedPerson.EmailAddresses.ToList()[1].Email);
}

The tests are straightforward, following the same structure as the 1st test, using GetInMemoryPersonRepository to spin up a PersonRepository with an In Memory database behind it.

If you run the tests, all should be good.

The tests are also quick - on my machine the three tests took 7, 13 and 624 ms.

If you to learn about using React with ASP.NET Core you might find my book useful:

ASP.NET Core 5 and React

ASP.NET Core 5 and React
Find out more

Want more content like this?

Subscribe to receive notifications on new blog posts and courses

Required
© Carl Rippon
Privacy Policy