Geeks With Blogs

News Please visit me at my new blog!!

profile for Aligned at Stack Overflow, Q&A for professional and enthusiast programmers
"free in Christ Jesus from the law of sin and death." Romans 8:2 (ESV) Check out the Falling Plates video on YouTube.
more about the Gospel
And then listen to Francis Chan speaking at LifeLight in SD.



Programming and Learning from SD

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<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.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<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},
    }));
    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<Product> Products = new List<Product>(); 

    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<T> where T : class
{
    public static DbSet<T> GetFake(List<T> data)
    {
        var dataAsQueryable = data.AsQueryable();
        var fakeDbSet = A.Fake<DbSet<T>>(b => b.Implements(typeof(IQueryable<T>)));
        A.CallTo(() => ((IQueryable<T>)fakeDbSet).GetEnumerator()).Returns(dataAsQueryable.GetEnumerator());
        A.CallTo(() => ((IQueryable<T>)fakeDbSet).Provider).Returns(dataAsQueryable.Provider);
        A.CallTo(() => ((IQueryable<T>)fakeDbSet).Expression).Returns(dataAsQueryable.Expression);
        A.CallTo(() => ((IQueryable<T>)fakeDbSet).ElementType).Returns(dataAsQueryable.ElementType);
        return fakeDbSet;
    }
}
Posted on Friday, November 20, 2015 9:11 PM Unit Testing , Mocking | Back to top


Comments on this post: FakeItEasy and EntityFramework

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Aligned | Powered by: GeeksWithBlogs.net