Transactional Integration Testing ASP.Net Core and Entity Framework Core

.net-core asp.net asp.net-core c# entity-framework-core

Question

I’m curious if anyone has gone down the road of transactional integration testing with aspnet and ef core? I want to be able to perform full integration tests all the way to the db (not using an in-memory db). There are 2 problems:

  • Tests can have side effects, but should be run in isolation since side effects could cause other tests to fail. I don’t want the devs to be required to write excessive cleanup code after each test.
  • I can teardown and recreate the db every test run but as the test counts start reaching the 100s it becomes unbearably slow to run the tests.

I would like to wrap tests in a transaction (_dbContext.Database.BeginTransactionAsync()). The problem is the DbContext I get from:

_server = new TestServer(builder);
_services = _server.Host.Services;
_dbContext = (AppDbContext)_services.GetService(typeof(AppDbContext))

Will be in a different scope (so a different instance) than the one that gets resolved by the AspNetCore middleware. So, only the test code would be transactional, not any code executed by the TestServer. I have considered using some test middleware in a TestStartup class that would wrap the API code in a transaction, but the problem there is it will be disposed/rolled back before the test can evaluate it. Consider the following use case:

  • send POST to create resource
  • assert the dbContext contains the resource

In this case, the test needs access to the same dbContext instance used by the test server. I tried a few hacky ways of passing the context using AsyncLocal which didn’t work so then I just tried using a simple static member. But, that also didn’t work, so it appears there is some AppDomain isolation between the test app and the TestServer. I’m curious if anyone has gone down this road and if so, what they came up with?

1
2
12/11/2017 3:57:47 PM

Accepted Answer

Just closing out this issue. The solution was to register the DbContext as a singleton in the test startup class. So, in tests:

services.AddDbContext<HostContext>(Configure, ServiceLifetime.Singleton);

But, in the application it would be registered as:

services.AddDbContext<HostContext>(Configure, ServiceLifetime.Transient);

UPDATE

A more complete answer has been posted here http://nance.io/leveling-up-your-dotnet-testing-transactional-integration-testing-in-asp-net-core/

1
4/15/2018 12:06:21 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow