rgvlee/EntityFrameworkCore.Testing

v5.x -- Mocked DB context is disposed and I can't verify entities were added/updated

Closed this issue · 5 comments

I couldn't find a Discord or Slack or anything to just ask this question, so I'm sorry if this is the wrong place to seek advice.

Using the EntityFrameworkCore.Testing.NSubstitute v 5.0.0

// Arrange

 var options = new DbContextOptionsBuilder<ApplicationDbContext>()
     .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
     .Options;

 var dbContextToMock = new ApplicationDbContext(options);

 var _dbContext = new MockedDbContextBuilder<ApplicationDbContext>()
     .UseDbContext(dbContextToMock)
     .UseConstructorWithParameters(options)
     .MockedDbContext;

  var _dbContextFactory = Substitute.For<IDbContextFactory<ApplicationDbContext>>();
 _dbContextFactory.CreateDbContext().Returns(_dbContext );
 _dbContextFactory.CreateDbContextAsync().Returns(Task.FromResult(_dbContext ));
 
  var testItem = new TestItem{ Id = 55555 };

  _dbContext.MockedDbContext.Set<TestItem>();
  _dbContext.MockedDbContext.LoanTicklerItems.Add(testItem );

  await _dbContext.MockedDbContext.SaveChangesAsync();

 // ACT
 
 (This is inside the tested service)
 
 using context = _dbContext.CreateContext();
 
 context.TestItems.Add(new TestItem { Id = 66666 });
  
 // ASSERT
 
 _dbcontext.TestItems.Should().HaveCount(2)  <-- This throws a System.ObjectDisposedException

I'm not sure how I can assert on _dbContext if the method under test disposes of it (which is what I want to happen in a non-test situation)

Help?

If I read this correctly, you're injecting a DB context factory into your service, then using that to create the DB context?

That's kinda correct -- I'm injecting a mocked DB context factory that's been setup to deliver the mocked DB context.

Yeah same same; I'm referring to how the implementation works. Then based on that your using statement disposes of the db context.

This feels like something you'd have a problem with with any object. The usual use case would be to inject the db context into the service and let the DI container handle lifetime and disposal. That makes it easier to test.

Given you are using the in-memory provider and passing a db context instance to the mock, have you tried inspecting dbContextToMock and asserting on that? As at the end of the day the mock is interacting directly it, the in-memory provider is providing the functionality for most of the mock. To add to that, what is your use case for using a mocked db context?

If the above doesn't hold I would need more of the implementation to advise.

As another idea, I believe the in-memory provider maintains state provided you use the same databaseName. So your assert may be able to be done off of another db context instance.

As another idea, I believe the in-memory provider maintains state provided you use the same databaseName. So your assert may be able to be done off of another db context instance.

This worked! Thank you.

I totally missed that part in my setup (I've been using it forever, but only now started using the factory pattern).