2021年4月28日星期三

Why does .NET Core scope affect how db context updates are visible?

I've discovered some interesting behaviour with .NET dbContext and scoping in a unit test, and I haven't been able to figure out why this is happening. Hopefully someone will know why this is.

This is from a test method. Here are the steps. I've tried to edit it down for clarity.

  1. Test class Setup adds the required services for dependency injection, and creates the database as an InMemory db, and seeds the test data.
... add services ...   services.AddDbContext<ApplicationDbContext>(options => options.UseInMemoryDatabase("ApplicationDb"));  _serviceProvider = services.BuildServiceProvider();  _serviceScopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();  _dbContext = _serviceProvider.GetRequiredService<MyDbContext>();  ... seed data ...  
  1. Test Method modifies some data, then calls the target method being tested.
//signature: public async Task TargetMethod(SomeTaskDto taskDto, IServiceScopeFactory serviceScopeFactory)  ... modify some data using _dbContext created in Setup ...  var _myClass =_serviceProvider.GetRequiredService<MyClass>();  await _myClass.TargetMethod( taskDto, _serviceScopeFactory );  
  1. Target method then uses _serviceScopeFactory to get a db context and modify some data.
 using (var scope = serviceScopeFactory.CreateScope())              {                  var _db = scope.ServiceProvider.GetService<MyDbContext>();  ... changes made by calling test method are visible here.  ... modify some data ...                  await _db.SaveChangesAsync();  ... other stuff ...            } //end scope  
  1. Back in the test method, after calling the target method, the changes are not visible in the original db context:
  var entityShouldBeModified = _dbContext.Products.Where( x => x.Id = idOfModifiedEntity ).FirstOrDefault();    //this fails:    Assert.AreEqual( expectedUpdatedValue, entityShouldBeModified.PropertyWhichShouldBeModified );  
  1. If I modify the test method to instead create a new scope after calling the target method, and get a new db context, the updated data from the target method is now visible:
   using(var scope = _serviceScopeFactory.CreateScope())              {                  var db = scope.ServiceProvider.GetService<MyDbContext>();                  db.SetAuthenticatedUser(_user);                   var entityShouldBeModified = db.Products.Where( x => x.Id = idOfModifiedEntity ).FirstOrDefault();                 //this works:                 Assert.AreEqual( expectedUpdatedValue, entityShouldBeModified.PropertyWhichShouldBeModified );            }  

Is this only something that happens with InMemory dbs in unit testing? (I guess I should really try it out on a Sql Server db.) Even if it's only on InMemory dbs, why are the changes made by the test method visible to the target method, but the changes made by the target method are NOT visible to the calling test method?

Why did I have to create a new scope and new db context to see the changes made by the target method?

Thanks, any explanations appreciated.

https://stackoverflow.com/questions/67310184/why-does-net-core-scope-affect-how-db-context-updates-are-visible April 29, 2021 at 10:18AM

没有评论:

发表评论