FakeItEasy and EntityFramework

We needed to fake or mock out Entity Framework so that we could test our “service layer” that holds our business logic without hitting a real database. We are using EF as our Repository and skipping all the extra work in creating a repository code layer that only wraps EF. We are ok with being this closely tied to EF.

It was difficult to figure out how to fake the context with an interface we made ourselves. We found some helpful Nuget packages, so I decided to share it.

EntityFramework.Testing:

EntityFramework Testing

EntityFramework.Testing.FakeItEasy:

EntityFrameworkTesting.FakeItEasy NuGet package

Looking at the project site for EntityFramework.Testing, they have some sample code for FakeItEasy as well as other mocking frameworks.

EntityFramework.Testing Project site

EntityFramework.Testing.FakeItEasy provides a helpful extension method to mock EntityFramework's DbSets using FakeItEasy.

This also supports Moq and other libraries.

Sample code using it:

using System.Collections.Generic; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; using Acme.Data; using Acme.Models; using FakeItEasy; using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Acme.Services.Tests { [TestClass] public class ProductServiceTests { [TestMethod] [TestCategory("Product Service Get")] public void Get_All_ReturnsExpected() { // Create test data var testData = new List { new Product {ProductId = 1, Name = "Product 1", Description = "this is a description", Active = true}, new Product {ProductId = 2, Name = "Product 2", Description = "this is a description", Active = true}, new Product {ProductId = 3, Name = "Product 3", Description = "this is a description", Active = false}, new Product {ProductId = 4, Name = "Product 4", Description = "this is a description", Active = true}, };

        // Arrange
        var set = A.Fake<DbSet<Product>>(o => o.Implements(typeof(IQueryable<Product>)).Implements(typeof(IDbAsyncEnumerable<Product>)))
                    .SetupData(testData);

        var context = A.Fake<AcmeContext>();
        A.CallTo(() => context.Products).Returns(set);

        var productService = new ProductService(context);

        // Act
        var products = productService.GetAll().ToList();

        // Assert
        Assert.AreEqual(4, products.Count(), "Should have 4");
        Assert.AreEqual(1, products.First().ProductId, "Should be 1");
    }

    \[TestMethod\]
    \[TestCategory("Product Service Get")\]
    public void Get\_Active\_OnlyReturnsActive()
    {
        // Create test data
        var testData = new List<Product>
        {
            new Product {ProductId = 1, Name = "Product 1", Description = "this is a description", Active = true},
            new Product {ProductId = 2, Name = "Product 2", Description = "this is a description", Active = true},
            new Product {ProductId = 3, Name = "Product 3", Description = "this is a description", Active = false},
            new Product {ProductId = 4, Name = "Product 4", Description = "this is a description", Active = true},
        };

        // Arrange
        var set = A.Fake<DbSet<Product>>(o => o.Implements(typeof(IQueryable<Product>)).Implements(typeof(IDbAsyncEnumerable<Product>)))
                    .SetupData(testData);

        var context = A.Fake<AcmeContext>();
        A.CallTo(() => context.Products).Returns(set);

        var productService = new ProductService(context);

        // Act
        var products = productService.GetActiveProducts().ToList();

        // Assert
        Assert.AreEqual(3, products.Count(), "Should have 3");
        Assert.AreEqual(4, products.Last().ProductId, "Should be 4");
        Assert.IsFalse(products.Any(x =>x.Active == false), "None should be active");
    }
}

}

Here’s an alternative a co-worker had created before the NuGet package was discovered.

The test:

[TestMethod] [TestCategory("Product Service Get")] public void Get_All_ReturnsExpected() { // Arrange var contextFaker = new ContextFaker(); contextFaker.Products.AddRange(new List { new Product { ProductId = 1, Name="Product 1", Description = "this is a description", Active = true}, new Product { ProductId = 2, Name="Product 2", Description = "this is a description", Active = true}, new Product { ProductId = 3, Name="Product 3", Description = "this is a description", Active = false}, new Product { ProductId = 4, Name="Product 4", Description = "this is a description", Active = true}, })); var productService = new ProductService(contextFaker.FakeContext);

// Act
var products = productService.GetAll().ToList();

// Assert
Assert.AreEqual(4, products.Count(), "Should have 4");
Assert.AreEqual(1, products.First().ProductId, "Should be 1");

}

The helper code:

public class ContextFaker { public List Products = new List();

private IAcmeContext \_fakeContext;

public IAcmeContext FakeContext
{
    get
    {
        A.CallTo(() => \_fakeContext.Products).Returns(ListFaker<Product>.GetFake(Products));
        return \_fakeContext;
    }
    set { \_fakeContext = value; }
}

public ContextFaker()
{
    \_fakeContext = A.Fake<IAcmeContext>();
}

}

public static class ListFaker where T : class { public static DbSet GetFake(List data) { var dataAsQueryable = data.AsQueryable(); var fakeDbSet = A.Fake<DbSet>(b => b.Implements(typeof(IQueryable))); A.CallTo(() => ((IQueryable)fakeDbSet).GetEnumerator()).Returns(dataAsQueryable.GetEnumerator()); A.CallTo(() => ((IQueryable)fakeDbSet).Provider).Returns(dataAsQueryable.Provider); A.CallTo(() => ((IQueryable)fakeDbSet).Expression).Returns(dataAsQueryable.Expression); A.CallTo(() => ((IQueryable)fakeDbSet).ElementType).Returns(dataAsQueryable.ElementType); return fakeDbSet; } }

This article is part of the GWB Archives. Original Author: Aligned

New on Geeks with Blogs