4

I'm mocking a DbContext to auto-test classes that update the database.

I'm using Entity Framework Core and .NET 5.

Mock<MyDbContext> fakeDbContext = new Mock<MyDbContext>();

List<Book> availableBooks = new List<Book>(); // filled elsewhere

fakeDbContext.Setup(ct => ct.BookRepository).ReturnsDbSet(availableBooks);  

This works fine, up to

fakeDbContext.BookRepository.Add(newBook);

The data from newBook show neither in BookRepository not in availableBooks.

So I guess I have to mock Add() further (I thought Setup().ReturnsDbSet() handled that, mistakenly it appears).

That would be the easiest way to call availableBooks.Add(). However, it has to return an EntityEntry<Book> object, which I haven't yet found how to create (it has a constructor, but not recommended for regular use).

I can't find any documentation on the matter, however. What can I try next?

18
  • 2
    Are using this by any chance: github.com/MichalJankowskii/Moq.EntityFrameworkCore ? Commented Jul 24 at 12:43
  • 1
    I looked into their examples and found that you probably need to do something like this: dotnetfiddle.net/W1YFC3 Commented Jul 24 at 13:18
  • 1
    ^^ And that's because you are supposed to assume the DB operation was successful (you are NOT testing EFCore nor the Database, your "Unit" is the thing that is using the DbSet). Commented Jul 24 at 13:23
  • 1
    I just looked into some legacy code of ours and we were using MockQueryable, when we used to use Moq. I remember that there were some tests that were similar to yours. If I remember correctly, there may still be some setting up to do, though. Commented Jul 24 at 13:45
  • 1
    @Fildor: indeed, the "Moq.EntityFrameworkCore vs MockQueryable" section in this article I started out with states almost plainly that I should use MockQueryable for DB operations. I'm going to give it a try. Commented Jul 24 at 13:52

2 Answers 2

2

It being understood that the right answer is this one, I also want the question to get a straight answer, if nothing else because a few people upvoted it.

As mentioned in the comments, I tried Moq.EntityFrameworkCore and failed.

I succeeded with MockQueryable:

Mock<MyDbContext> fakeDbContext = new Mock<MyDbContext>();

List<Book> availableBooks = new List<Book>(); // filled elsewhere

Mock<DbSet<Book>> fakeBookRepository = availableBooks.AsQueryable().BuildMockDbSet();
fakeBookRepository.Setup(rp => rp.Add(It.IsAny<Book>()))
                  .Callback((Book bk) => availableBooks.Add(bk));
PseudoContexteMAS.Setup(ct => ct.DepotLivraison)
                 .Returns(fakeBookRepository.Object);

There ya go.

Sign up to request clarification or add additional context in comments.

Comments

0

First, Steve Py* is more than very likely right: what I'm doing here amounts to testing my repository. Which I should have no business doing.

So, well, that's the main answer here.

The point of a using a Repository is to provide a boundary for testing business logic around EF. The repository itself should not require unit testing. The end to end behaviour from data through to the application should be covered by integration tests that talk to a real database instance with known test data state. Have the repository return IQueryable then mock the repository to return the MockQueryable built mock.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.