Mocking DbSet<TEntity> in Repository

Viewed 3379

I want to unit-test the retrieval methods from a repository which has a mocked DbContext, but I am not able to set the mocked DbSet values to the repository.

The Repository looks like this:

public class ChangeLogRepository : Repository<ChangeLog>, IChangeLogRepository
{
    public ChangeLogRepository(IDbContext context, long tenantId) : base(context, tenantId)
    {
    }
}

The base class:

public class Repository<TEntity> where TEntity : class {
    protected readonly IDbContext Context;
    protected DbSet<TEntity> Entities { get; set; }
    public long TenantId { get; set; }

    protected Repository(IDbContext context, long tenant)
    {
        Context = context;
        TenantId = tenant;
        Entities = Context.Set<TEntity>();
    }
    public List<TEntity> GetAll()
    {
        return Entities.ToList();
    }
    //..
}

Last but not least, the test class:

[TestClass]
public class ChangeLogRepository_Test
{
    private ChangeLogRepository repository;
    private List<ChangeLog> allTestData;

    [TestInitialize]
    public void TestInitialize()
    {
        var dbContext = new Mock<IDbContext>();
        allTestData = new List<ChangeLog>() {
            new ChangeLog { Id = 10, EntityName = "User",PropertyName = "UserName",PrimaryKeyValue = 1,OldValue = "Max",NewValue = "Moritz",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Default },
            new ChangeLog { Id = 10, EntityName = "User",PropertyName = "CreatedAt",PrimaryKeyValue =2,OldValue = "15/06/2017",NewValue = "15/06/2017",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Date },
            new ChangeLog { Id = 10, EntityName = "Role",PropertyName = "RoleName",PrimaryKeyValue = 56,OldValue = "Admin",NewValue = "Administrator",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Default },
        };
        var changelogs = MockDbSet(allTestData);
        dbContext.Setup(m => m.Set<ChangeLog>()).Returns(() => changelogs);
        repository = new ChangeLogRepository(dbContext.Object, 10);
    }

    [TestMethod]
    public void Setup_Test()
    {
        Assert.AreEqual(repository.GetAll(), allTestData);
    }
    private static DbSet<T> MockDbSet<T>(IEnumerable<T> list) where T : class, new()
    {
        IQueryable<T> queryableList = list.AsQueryable();
        Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
        dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
        dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
        dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
        dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(queryableList.GetEnumerator());
        return dbSetMock.Object;
     }
}

If I run it, the test fails, because the getAll() method retuns null. It seams, that the property 'Entities' wasn't correctly initialized by the mocked Set() method.

When I set a breakpoint in the repository-constructor and examine the Entities property, under 'Expression > Value > Result View' the three Entries appear. Under the first Result View there are one "Enumeration yielded no results" message and two rows with ? in it (Visual Studio 2017).

How can I mock the entities in the repository correctly? What am I doing wrong?

2 Answers
Related