How do I go about unit testing with Entity Framework and Moq?

Viewed 10865

I'm new to Moq, and wanting to use it like a backing store for data - but without touching the live database.

My setup is as follows:

  • A UnitOfWork contains all repositories, and is used for data access throughout the application.
  • A Repository represents a direct hook into a DbSet, provided by a DbContext.
  • A DbContext contains all DbSets.

Here is my test so far:

        // ARRANGE
        var user = new User()
        {
            FirstName = "Some",
            LastName = "Guy",
            EmailAddress = "some.guy@mockymoqmoq.com",
        };

        var mockSet = new MockDbSet<User>();
        var mockContext = new Mock<WebAPIDbContext>();

        mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object);

        // ACT
        using (var uow = UnitOfWork.Create(mockContext.Object))
        {
            uow.UserRepository.Add(user);
            uow.SaveChanges();
        }

        // ASSERT
        mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once());

My test seems to be successful, as it can verify that a user was added to the mock DbSet - but what I need to do is actually get that data back and perform further assertions on it (this is just an ad-hoc test).

Please advise, testing frameworks are doing my head in. Also, I have the option to move to other testing frameworks if they are easier to use.

Thank you.

Update: Here is my working code.

Unit Test

        // ARRANGE
        var user = new User()
        {
            FirstName = "Some",
            LastName = "Guy",
            EmailAddress = "some.guy@mockymoqmoq.com",
        };

        var mockSet = new MockDbSet<User>();
        var mockContext = new Mock<WebAPIDbContext>();

        mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object);

        // ACT
        using (var uow = UnitOfWork.Create(mockContext.Object))
        {
            uow.UserRepository.Add(user);
            uow.SaveChanges();
        }

        // ASSERT
        mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once());

        // TODO: Further assertations can now take place by accessing mockSet.BackingStore.
    }

MockDbSet

class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class
{
    public ICollection<TEntity> BackingStore { get; set; }

    public MockDbSet()
    {
        var queryable = (this.BackingStore ?? (this.BackingStore = new List<TEntity>())).AsQueryable();

        this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider);
        this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression);
        this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType);
        this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator());

        // Mock the insertion of entities
        this.Setup(e => e.Add(It.IsAny<TEntity>())).Returns((TEntity entity) =>
        {
            this.BackingStore.Add(entity);

            return entity;
        });

        // TODO: Other DbSet members can be mocked, such as Remove().
    }
}
1 Answers
Related