Unit test enity framework generic repository using Moq

c# entity-framework moq repository unit-testing

Question

Structure:

  • DAL - entity framework, generic repository, unit of work
  • BLL - service, automapper (mapping entity generated classes/objects to business objects)
  • Interface - iservice
  • Model - business objects Web - mvc
  • Test - unit test

Generic Repository

public class EntityRepository<T> : IEntityRepository<T> where T : class
{
    internal MyDB_Entities context;
    internal DbSet<T> dbSet;

    public EntityRepository(MyDB_Entities context)
    {
        this.context = context;
        this.dbSet = context.Set<T>();
    }

    public virtual T GetByID(object id)
    {
        return dbSet.Find(id);
    }

    // more code
}

Interface for Generic Repository

public interface IEntityRepository<T> where T : class
{ 
    IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "");
    T GetByID(object id);
    // more code
}

Unit of Work

public class UnitOfWork : IUnitOfWork, IDisposable
{
    MyDB_Entities _context;
    public IEntityRepository<Customer> customerRepository { get; set; }
    public IEntityRepository<Product> productRepository { get; set; }

    public UnitOfWork(MyDB_Entities context)
    {
        _context = context;
        customerRepository = new EntityRepository<Customer>(_context);
        productRepository = new EntityRepository<Product>(_context); 
    }

    public void Save()
    {
        _context.SaveChanges();
    }
    // more code
}

Interface for Unit Of Work

public interface IUnitOfWork
{
    IEntityRepository<Customer> customerRepository { get; set; }
    IEntityRepository<Product> productRepository { get; set; }
    void Dispose();
    void Save();
}

Service

public class SomeService : ISomeService 
{
    readonly IUnitOfWork _unitOfWork;
    public SomeService (IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
    // DoSomethingMethod
}

Interface for Service

public interface ISomeService
{
    // IDoSomethingMethod 
}

Extension

public static class MockDBSetExtension
{
    public static void SetSource<T>(this Mock<DbSet<T>> mockSet, IList<T> source) where T : class
    {
        var data = source.AsQueryable();
        mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);
        mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
        mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
        mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
    }
}

Test Class

[TestClass]
public class My_Test
{
    Mock<DbSet<Product>> _mockProductDBSet;
    Mock<MyDB_Entities> mockContext;

    [TestInitialize]
    public void TestInitialize()
    {
        _mockProductDBSet = new Mock<DbSet<Product>>();
        mockContext = new Mock<MyDB_Entities>();
        mockContext.Setup(s => s.Products).Returns(_mockProductDBSet.Object);
    }

    [TestMethod]
    public void TestMocking()
    {
       var prod = new Product() { ProductName= "AAA", ProductID = 1 };
        _mockProductDBSet.SetSource(new List<Product> { prod });
       // more code here (new up the service, then test the service method, etc)
    }
}

Question/Problem

I am not able to get a passing test because the Generic Repository class this.dbSet = context.Set(); is always null. As you can see I mockup the dbset and the context. I also setup the mocked context to return mocked DBSet. EnityRepository constructor takes the mocked context as expected, but this.dbSet = context.Set(); isn't picking up my mocked DBSet. I'm not sure what I did wrong. Am I not testing/mocking the right way?

1
5
6/16/2016 12:07:50 AM

Accepted Answer

Lets say you have a IProuctService defined as

public interface IProductService {
    string GetProductName(int productId);
}

where the concrete implementation depends on IUnitOfWork

public class ProductService : IProductService {
    readonly IUnitOfWork _unitOfWork;
    public ProductService(IUnitOfWork unitOfWork) {
        _unitOfWork = unitOfWork;
    }

    public string GetProductName(int productId) {
        var item = _unitOfWork.productRepository.GetByID(productId);

        if (item != null) {
            return item.ProductName;
        }

        throw new ArgumentException("Invalid product id");
    }
}

If the method under test is IProductService.GetProductName, here is an example of test that can be done.

[TestMethod]
public void ProductService_Given_Product_Id_Should_Get_Product_Name() {
    //Arrange
    var productId = 1;
    var expected = "AAA";
    var product = new Product() { ProductName = expected, ProductID = productId };

    var productRepositoryMock = new Mock<IEntityRepository<Product>>();
    productRepositoryMock.Setup(m => m.GetByID(productId)).Returns(product).Verifiable();

    var unitOfWorkMock = new Mock<IUnitOfWork>();
    unitOfWorkMock.Setup(m => m.productRepository).Returns(productRepositoryMock.Object);

    IProductService sut = new ProductService(unitOfWorkMock.Object);
    //Act
    var actual = sut.GetProductName(productId);

    //Assert
    productRepositoryMock.Verify();//verify that GetByID was called based on setup.
    Assert.IsNotNull(actual);//assert that a result was returned
    Assert.AreEqual(expected, actual);//assert that actual result was as expected
}

In this scenario there was no need to mock up DbSet or DbContext as the SUT had no need for the implementations of the dependent interfaces. They can be mocked to be used by the system under test.

8
6/16/2016 1:05:35 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow