Search code examples
c#asp.net-coreasp.net-web-apiintegration-testingxunit

Integration test with WebApplicationFactory fails with ObjectDisposedException for IServiceProvider


I have a simple health check test which looks like this:

public class HealthCheckEndpointTests : IClassFixture<ItemsApplicationFactory>
{
    private readonly ItemsApplicationFactory _factory;

    public HealthCheckEndpointTests(ItemsApplicationFactory factory)
    {
        _factory = factory;
    }

    public async Task HealthCheck_Test()
    {
       // Arrange
       HttpClient httpClient = _factory.CreateClient();

       // Act 
       string response = await httpClient.GetStringAsync("/health/live");

       // Assert
       Assert.Equal("Healthy", response);
    }
}

My ItemsApplicationFactory looks like this:

public class ItemsApplicationFactory : WebApplicationFactory<Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureKestrel(options => options.AllowSynchronousIO = true);


        builder.ConfigureServices(services =>
        {
            // remove db context options if exists 
            var dbContextDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ItemsDbContext>));
            if (dbContextDescriptor != null)
                services.Remove(dbContextDescriptor);

            var serviceCollection = new ServiceCollection()
                .AddEntityFrameworkInMemoryDatabase()
                .BuildServiceProvider();

            services.AddDbContext<ItemsDbContext>(mariaDb =>
            {
                mariaDb.UseInMemoryDatabase("template");
                mariaDb.UseInternalServiceProvider(serviceCollection);
            });
        });
    }
}

When I run the test, I get the following exception thrown

System.ObjectDisposedException : Cannot access a disposed object.
Object name: 'IServiceProvider'

I have changed my test, to see if the exception is caused by initialization of ItemsApplicationFactory or HttpClient. So the test looks like this

public class HealthCheckEndpointTests : IClassFixture<ItemsApplicationFactory>
{
    private readonly ItemsApplicationFactory _factory;

    public HealthCheckEndpointTests(ItemsApplicationFactory factory)
    {
        _factory = factory;
    }

    public async Task HealthCheck_Test()
    {
       // Arrange
       HttpClient httpClient = _factory.CreateClient();

       // Act 
       await Task.Run(() => Task.CompletedTask);

       // Assert
       Assert.True(true);
    }
}

The test did not throw any exception.

Why _factory.CreateClient(); does not throw, but httpClient.GetStringAsync("/health/live") does? And how to fix that?


Solution

  • I was experiencing the same. One possible reason is that something fails in the test execution but you are failing to find out what exactly, and the test shows that IServiceProvider was disposed.

    That's not the cause, but the consequence.

    Go to your Program.cs and wrap everything under a

    try {
       //...
    } catch(Exception exception) {
       // breakpoint here to find out the real reason
       throw; // do not forget to also throw the same exception
    }
    

    and debug the test. You'll see the real reason causing the error you're seeing.

    Careful not to swallow the exception. I'd log fatal error and throw;, but this is just for the purpose of finding out while debugging what's the real reason causing the problem.

    In my case it was one driver trying to connect to CosmosDb when the SSL was not trusted, but it could be anything.