dotnet/systemweb-adapters

API integration tests broken by 1.3.0

Closed this issue · 3 comments

It looks like systemweb adapters 1.3.0 breaks all our integration tests, testing Controller-based API's, using XUnit (latest version) with its IClassFixture and appling WebApplicationFactory and still using .NET 6. With systemweb adapters 1.2.0 all tests were green, with 1.3.0 at most one test is green, the rest fails. Running each test separately has the test always succeed.

The tests consistently fail with the following error:

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

  Stack Trace: 
ThrowHelper.ThrowObjectDisposedException()
ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
ServiceProvider.GetService(Type serviceType)
ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
WebApplicationFactory`1.ConfigureHostBuilder(IHostBuilder hostBuilder)
WebApplicationFactory`1.EnsureServer()
WebApplicationFactory`1.CreateDefaultClient(DelegatingHandler[] handlers)
WebApplicationFactory`1.CreateDefaultClient(Uri baseAddress, DelegatingHandler[] handlers)
WebApplicationFactory`1.CreateClient(WebApplicationFactoryClientOptions options)
WebApplicationFactory`1.CreateClient()
SuperSimpleTests.TestWhatever_WithoutCondition_DoesWhatever() line 19
--- End of stack trace from previous location ---

This seems to suggest somehow the TestServer instance is being disposed at an unfortunate moment.

This even happens for a test as simple as (and seemingly totally isolated from the other tests)...

public class SuperSimpleTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;

    public SuperSimpleTests(WebApplicationFactory<Program> factory) => _factory = factory;

    [Fact]
    public async Task TestWhatever_WithoutCondition_DoesWhatever()
    {
        //  Arrange
        var client = _factory.CreateClient();

        //  Act
        var response = await client.GetAsync("/");

        //  Assert
        response.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }
}

...when this is made part of the set of API tests.

All our main API tests follow the main construction for accessing a client as follows:

var client = _factory.WithWebHostBuilder(
   builder =>
   {
       builder.ConfigureTestServices(services =>
       {
            // Add or replace some services...
       });
       builder.UseConfiguration(new ConfigurationBuilder()
                                            .AddJsonFile(AppsettingsTestJson)
                                            .Build());
   }).CreateClient(new WebApplicationFactoryClientOptions { BaseAddress = _address });

whereby the error obviously pops up at the CreateClient() call.

Can you share an example repro? The stacktrace alone is not giving enough info to pinpoint anything specific.

Between 1.2 and 1.3, the lifetime of a couple of things that were per-request were moved to be per-host to better mimic ASP.NET Framework behavior. For example, HttpRuntime and HostingEnvironment APIs, so maybe something there is causing this?

For reference, this is how we recommend testing it with the TestServer tools: https://learn.microsoft.com/en-us/aspnet/core/migration/inc/unit-testing. I have not tried it with the WebApplicationFactory pattern.

Closing out the issue as we discussed offline and found the issue to be that WithWebHostBuilder creates a new host which will try to set the HttpRuntime. Ensuring that this and the original host is disposed fixed the issue.