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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions