Last post Jul 10, 2019 01:33 AM by uid265813
Apr 30, 2019 04:36 PM|abbitha7|LINK
I have a unit test that calls on a DBContext mocked using Moq. The function being tested does this before calling AddAsync and SaveChangesAsync:
context.ChangeTracker.Entries().Where(e => e.Entity != null).ToList().ForEach(e => e.State = EntityState.Detached);
In my unit test, I get an error that ChangeTracker is null. Is there a way for me to Moq this so it's not null?
This is the test I have tried, but it does not work. I get an error that the constructor argument for mockChangeTracker is not the correct type.
var mockSet = new Mock<DbSet<DataFile>>();
var mockContext = new Mock<DataModelerContext>();
mockContext.Setup(m => m.DataFile).Returns(mockSet.Object);
mockContext.Setup(m => m.AddAsync(It.IsAny<DataFile>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult((EntityEntry<DataFile>)null));
mockContext.Setup(m => m.SaveChangesAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(1));
IEnumerable<EntityEntry> entries = new List<EntityEntry>();
var mockChangeTracker = new Mock<ChangeTracker>(MockBehavior.Strict, mockContext.Object);
mockChangeTracker.Setup(c => c.Entries()).Returns(entries);
mockContext.Setup(m => m.ChangeTracker).Returns(mockChangeTracker.Object);
var mockServiceProvider = new Mock<IServiceProvider>();
mockServiceProvider.Setup(sp => sp.GetService(It.IsAny<Type>())).Returns(mockContext.Object);
DatabaseRepository databaseRepository = new DatabaseRepository(mockServiceProvider.Object);
bool succesfullyAddedToDbSet = await databaseRepository.AddNewEntryToDatabaseAsync(new DataFile(), "DataFile");
I realize I shouldn't mock the class directly, but I haven't had any luck trying to do the interface that ChangeTracker implements (IInfrasctructure<IStateManager>). Is there a better way to do this?
Apr 30, 2019 09:35 PM|deepalgorithm|LINK
Not sure if this is your issue, but you should not try to mock out the DbContext. You should use the provided in-memory implementation.
Instead, you should do something like this:
See section Writing Tests
May 01, 2019 02:14 PM|bruce (sqlwork.com)|LINK
also you generally mock the repository, rather than the actual dbcontext.
May 02, 2019 08:52 AM|DA924|LINK
IMHO it's a waste of time trying to unit test EF. What should be unit tested and mocked out is the Repository object or the Data Access Object that would be using the low level database access technology.
May 07, 2019 07:25 PM|Metonymy|LINK
I guess the easiest is to refactor the tests to use in-memory database of EF Core. Please see https://docs.microsoft.com/en-us/ef/core/providers/in-memory/ for details. Also, for
seeding the in-memory database checkout https://github.com/AutoFixture/AutoFixture.
Sometimes, in .Net Core, the easiest way of doing things is the correct way of doing them.
If you're doing too many mocks you'll ending up testing how the functionality is implemented and not the desired behaviour, erros can slip by and tests become harder to maintain.
Hope you figure it out, cheers!
Jul 10, 2019 01:33 AM|uid265813|LINK
I would avoid mocking the DbContext if all possible. Use the in-memory provider if you need it in your tests.
There are of course exceptions; if you are using FromSql, ExecuteSqlCommand or DbQuery properties (basically anything relational), or you want access to mock verify functions then I would suggest looking at one of the existing NuGet packages that do these
Having authored EntityFrameworkCore.DbContextBackedMock.Moq I
can say with confidence there is a lot to set up and it is not straightforward. I only wrote it as there was nothing around that handled all of the above mentioned cases.