Skip to content

Run tests in parallel using WebApplicationFactory throw exception #577

@wondertalik

Description

@wondertalik

In api project i use Microsoft.FeatureManagement library and it works until i want to run tests in parallel.

to fix the problem i tried to put lock and it works, but it's the same that run then tests sequentially

    // Static lock to prevent concurrent host/server initialization across factory instances
    // This prevents race conditions in service registration (e.g., AddFeatureManagement)
    // while still allowing each test class to have its own factory instance
    private static readonly object _hostCreationLock = new object();


    /// <summary>
    /// Override CreateHost to synchronize host creation across parallel factory instances.
    /// This ensures service registration (including AddFeatureManagement) happens sequentially,
    /// preventing race conditions while still allowing parallel test execution.
    /// </summary>
    protected override IHost CreateHost(IHostBuilder builder)
    {
        lock (_hostCreationLock)
        {
            return base.CreateHost(builder);
        }
    }
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class CustomWebApplicationFactory : WebApplicationFactory<AssemblyMarker>
{

    private HttpMessageHandler? _optiConfigHttpMessageHandler;

    public void SetOptiConfigHttpMessageHandler(HttpMessageHandler handler)
    {
        _optiConfigHttpMessageHandler = handler;
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // Configure logging for tests
            services.AddLogging(logging =>
            {
                logging.ClearProviders();
                logging.AddSimpleConsole(options =>
                {
                    options.SingleLine = true;
                    options.TimestampFormat = "HH:mm:ss.fff ";
                    options.UseUtcTimestamp = true;
                    options.IncludeScopes = false;
                });
                logging.SetMinimumLevel(LogLevel.Debug);
            });
        });
    }
    
}


using Api.Private.IntegrationTests.Infrastructure;
using Identity.Tests.Shared.Mocking.ExternalIdentityProvider;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;

namespace Api.Private.IntegrationTests.GraphQL.Dashboards.OptiLeads;

public class GetSalesRealisedTests : IClassFixture<CustomWebApplicationFactory>, IDisposable
{
    private readonly IServiceScope _scope;

    private readonly IPrivateClient _client;

    private readonly HttpClient _httpClient;

    private readonly ITestContextAccessor _testContextAccessor;

    public GetSalesRealisedTests(
        CustomWebApplicationFactory factory,
        ITestContextAccessor testContextAccessor)
    {
        _testContextAccessor = testContextAccessor;

        // Create a scope from the factory's services
        _scope = factory.Services.CreateScope();

        // Configure the test HttpClient with the correct BaseAddress
        _httpClient = factory.CreateClient();
        _httpClient.BaseAddress =
            new Uri(_httpClient.BaseAddress ?? new Uri("http://localhost"), "/graphql-private");
        factory.Server.PreserveExecutionContext = true;

        // Register the TestHttpClientFactory in the scope
        var services = new ServiceCollection();
        services.AddSingleton<IHttpClientFactory>(_ => new TestHttpClientFactory(_httpClient));
        services.AddPrivateClient();

        var serviceProvider = services.BuildServiceProvider();
        _client = serviceProvider.GetRequiredService<IPrivateClient>();
    }

    [Fact]
    public async Task GetSalesRealised_ReturnsDataForUserWithPermissions()
    {
        
    }

    public void Dispose()
    {
        _scope.Dispose();
        _httpClient.Dispose();
    }
}
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
at Microsoft.FeatureManagement.FeatureManagementBuilder.AddFeatureFilter[T]()
at Microsoft.FeatureManagement.ServiceCollectionExtensions.GetFeatureManagementBuilder(IServiceCollection services)
at Microsoft.FeatureManagement.ServiceCollectionExtensions.AddFeatureManagement(IServiceCollection services)
at API.CompositionRoot.addFeatureManagements(IServiceCollection services) in /Users/admin/Works/NewOne/backend/src/API/CompositionRoot.fs:line 373
at API.CompositionRoot.compose(IConfiguration cfg, IServiceCollection services) in /Users/admin/Works/NewOne/backend/src/API/CompositionRoot.fs:line 399
at <StartupCode$API>.$Program.main@() in /Users/admin/Works/NewOne/backend/src/API/Program.fs:line 43
at InvokeStub_$Program.main@(Object, Object, IntPtr*)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions