I try to test my app so I need to mock my EF context.
My code seems to be ok, but I have following exception:
"System.ArgumentNullException : Value cannot be null. Parameter name: source"
Here is my test method:
var options = new DbContextOptionsBuilder<ProductContext>().Options;
var settings = new SqlSettings
{
InMemory = true
};
var context = new Mock<ProductContext>(options, settings);
var mockTreeService = new TreeService(context.Object);
await mockTreeService.CreateTreeAsync("Testing tree", Guid.NewGuid());
context.Verify(x => x.AddAsync(It.IsAny<Tree>(), CancellationToken.None), Times.Once);
It looks like that this exception is thrown during executing this piece of code
var tree = await _context.Trees
.Include(x => x.Translation)
.FirstOrDefaultAsync(x => x.Translation.Pl == name);
It comes from my service which I'm testing
I have used this https://github.com/huysentruitw/entity-framework-core-mock library. Very easy and can write unit test using less coding.
You can use most of Moq methods if you are using moq framework.
Below is example code for test DBQuerys.
public async Task<Boat> GetByIdAsync(string id)
=> await _boatContext.Boats.Where(x => x.id == id).FirstOrDefaultAsync();
[Fact]
public async Task GetByIdAsync_WhenCalled_ReturnsItem()
{
// Arrange
var models = new[] { new Boat { id = "p1" } };
var dbContextMock = new DbContextMock<BoatContext>();
dbContextMock.CreateDbQueryMock(x => x.Boats, models);
var service = new Properties(dbContextMock.Object);
// Act
var okResult = await service.GetByIdAsync("p1");
// Assert
Assert.IsType<Boat>(okResult.Result);
}
Posting here this may help someone :)
I think this is due to not having a connection string set. Frankly, it's a bit difficult to fully mock out DbContext
, which is why the EF Core team has provided an in-memory implementation. This is far easier to work with for testing purposes. Just change your options
initialization to:
var options = new DbContextOptionsBuilder<ProductContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
Afterwards, you'll need to populate the database with your test data. Then, you can run the rest of your test.
Note: if you're using the in-memory database, you don't need to mock the context anymore, so you can remove that bit of code. The in-memory database is essentially, itself, a mock.
Try to use my Moq/NSubstitute extension MockQueryable: https://github.com/romantitov/MockQueryable supported all Sync/Async operations
//1 - create a List<T> with test items
var users = new List<UserEntity>()
{
new UserEntity,
...
};
//2 - build mock by extension
var mock = users.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);
//3 - setup the mock as Queryable for NSubstitute
_userRepository.GetQueryable().Returns(mock);
DbSet also supported
//2 - build mock by extension
var mock = users.AsQueryable().BuildMockDbSet();
//3 - setup DbSet for Moq
var userRepository = new TestDbSetRepository(mock.Object);
//3 - setup DbSet for NSubstitute
var userRepository = new TestDbSetRepository(mock);
Note:
I don't think it's correct to Mock
the DbContext
. You should be mocking
your repositories
in your testing... mocking
the DbContext
is you basically testing Microsoft's
code... which is dumb because they already do that. So again... all of your data access should go through repositories
(see Repository Pattern) and you should be mocking
those in your testing, not the DbContext
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With