-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Closed
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
My CustomWebApplicationFactory need to cleanup the database in Dispose:
namespace Web.Api.IntegrationTests;
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
private IServiceCollection _services;
private ServiceProvider _sp;
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTests");
builder.ConfigureServices((context, services) =>
{
// Create a new service provider.
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextPool<AppDbContext>));
services.Remove(descriptor);
descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextPool<AppIdentityDbContext>));
services.Remove(descriptor);
services.AddDbContextPool<AppIdentityDbContext>(options =>
{
options.UseNpgsql(context.Configuration.GetConnectionString("IntegrationTests"), b => b.MigrationsAssembly("Web.Api.Infrastructure"));
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
options.LogTo(Console.WriteLine);
})
.AddDbContextPool<AppDbContext>(options =>
{
options.UseNpgsql(context.Configuration.GetConnectionString("IntegrationTests"), b => b.MigrationsAssembly("Web.Api.Infrastructure"));
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
options.LogTo(Console.WriteLine);
});
services.AddLogging();
services.AddOptions();
services.Configure<GrpcConfig>(context.Configuration.GetSection(nameof(GrpcConfig)));
services.AddScoped<SignInManager<AppUser>>();
services.AddScoped<ILogger<UserRepository>>(provider =>
{
ILoggerFactory loggerFactory = provider.GetRequiredService<ILoggerFactory>();
return loggerFactory.CreateLogger<UserRepository>();
});
services.AddDistributedMemoryCache();
_services = services;
// Build the service provider.
_sp = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database contexts
using (var scope = _sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var appDb = scopedServices.GetRequiredService<AppDbContext>();
var identityDb = scopedServices.GetRequiredService<AppIdentityDbContext>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
// Ensure the database is created.
appDb.Database.EnsureCreated();
identityDb.Database.EnsureCreated();
try
{
// Seed the database with test data.
SeedData.PopulateTestData(identityDb, appDb);
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with test messages. Error: {ex.Message}");
}
}
});
}
public void Dispose()
{
//var sp = _services.BuildServiceProvider();
// Create a scope to obtain a reference to the database contexts
using (var scope = _sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var appDb = scopedServices.GetRequiredService<AppDbContext>();
var identityDb = scopedServices.GetRequiredService<AppIdentityDbContext>();
SeedData.CleanUpTestData(identityDb, appDb);
}
base.Dispose();
GC.SuppressFinalize(this);
}
}
and it throws the following exception:
Failed Web.Api.IntegrationTests.Controllers.ProtectedControllerIntegrationTests.CanAccessProtectedResourceAfterLogin [1 ms]
Error Message:
[Test Collection Cleanup Failure (Controller Test Collection)]: System.InvalidOperationException : The logger is already frozen.
Stack Trace:
at Serilog.Extensions.Hosting.ReloadableLogger.Freeze()
at Serilog.SerilogHostBuilderExtensions.<>c__DisplayClass3_1.<UseSerilog>b__1(IServiceProvider services)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Serilog.SerilogHostBuilderExtensions.<>c__DisplayClass3_1.<UseSerilog>b__3(IServiceProvider services)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.Diagnostics.Internal.ScopedLoggerFactory.Create(IServiceProvider internalServiceProvider, IDbContextOptions contextOptions)
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_0(IServiceProvider p)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_8(IServiceProvider p)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at ResolveService(ILEmitResolverBuilderRuntimeContext, ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IResettableService.ResetState()
at Microsoft.EntityFrameworkCore.Internal.DbContextPool`1.Return(IDbContextPoolable context)
at Microsoft.EntityFrameworkCore.Internal.DbContextLease.Release()
at Microsoft.EntityFrameworkCore.Internal.ScopedDbContextLease`1.System.IDisposable.Dispose()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.Dispose()
at Web.Api.IntegrationTests.CustomWebApplicationFactory`1.Dispose() in /root/workspace/test/Web.Api.IntegrationTests/CustomWebApplicationFactory.cs:line 92
Using the code suggested in #46162 results in the followinng error:
Many functions are unavailable: SingleOrDefault, context, Remove, AddDbContextPool, etc:
public static async Task<CustomWebApplicationFactory<TStartup>> CreateWebApplicationFactory()
{
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "IntegrationTests");
var factory = new CustomWebApplicationFactory<TStartup>();
// Create a new service provider.
var descriptor = factory.Services.SingleOrDefault(d => d.ServiceType == typeof(DbContextPool<AppDbContext>));
factory.Services.Remove(descriptor);
descriptor = factory.Services.SingleOrDefault(d => d.ServiceType == typeof(DbContextPool<AppIdentityDbContext>));
factory.Services.Remove(descriptor);
factory.Services.AddDbContextPool<AppIdentityDbContext>(options =>
{
options.UseNpgsql(context.Configuration.GetConnectionString("IntegrationTests"), b => b.MigrationsAssembly("Web.Api.Infrastructure"));
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
options.LogTo(Console.WriteLine);
})
.AddDbContextPool<AppDbContext>(options =>
{
options.UseNpgsql(context.Configuration.GetConnectionString("IntegrationTests"), b => b.MigrationsAssembly("Web.Api.Infrastructure"));
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
options.LogTo(Console.WriteLine);
});
factory.Services.AddLogging();
factory.Services.AddOptions();
factory.Services.Configure<GrpcConfig>(context.Configuration.GetSection(nameof(GrpcConfig)));
factory.Services.AddScoped<SignInManager<AppUser>>();
factory.Services.AddScoped<ILogger<UserRepository>>(provider =>
{
ILoggerFactory loggerFactory = provider.GetRequiredService<ILoggerFactory>();
return loggerFactory.CreateLogger<UserRepository>();
});
factory.Services.AddDistributedMemoryCache();
// Create a scope to obtain a reference to the database contexts
using (var scope = factory.Services.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var appDb = scopedServices.GetRequiredService<AppDbContext>();
var identityDb = scopedServices.GetRequiredService<AppIdentityDbContext>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
// Ensure the database is created.
appDb.Database.EnsureCreated();
identityDb.Database.EnsureCreated();
try
{
// Seed the database with test data.
await SeedData.PopulateTestDataAsync(identityDb, appDb);
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with test messages. Error: {ex.Message}");
throw;
}
}
return factory;
}
And I need to set the ASPNETCORE_ENVIRONMENT and doing so in your suggested private constructor results in the following exception!
Failed Web.Api.IntegrationTests.SignalR.ChatHubTests.ReceiveMessageTest [1 ms]
Error Message:
System.AggregateException : One or more errors occurred. (Collection fixture type 'Web.Api.IntegrationTests.CustomWebApplicationFactory`1[[Program, Web.Api, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null]]' may only define a single public constructor.) (The following constructor parameters did not have matching fixture data: CustomWebApplicationFactory`1 factory)
---- Collection fixture type 'Web.Api.IntegrationTests.CustomWebApplicationFactory`1[[Program, Web.Api, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null]]' may only define a single public constructor.
---- The following constructor parameters did not have matching fixture data: CustomWebApplicationFactory`1 factory
Stack Trace:
----- Inner Stack Trace #1 (Xunit.Sdk.TestClassException) -----
----- Inner Stack Trace #2 (Xunit.Sdk.TestClassException) -----
Failed Web.Api.IntegrationTests.SignalR.ChatHubTests.ReceiveMessageFromUserTest [1 ms]
Error Message:
System.AggregateException : One or more errors occurred. (Collection fixture type 'Web.Api.IntegrationTests.CustomWebApplicationFactory`1[[Program, Web.Api, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null]]' may only define a single public constructor.) (The following constructor parameters did not have matching fixture data: CustomWebApplicationFactory`1 factory)
---- Collection fixture type 'Web.Api.IntegrationTests.CustomWebApplicationFactory`1[[Program, Web.Api, Version=7.0.0.0, Culture=neutral, PublicKeyToken=null]]' may only define a single public constructor.
---- The following constructor parameters did not have matching fixture data: CustomWebApplicationFactory`1 factory
Stack Trace:
----- Inner Stack Trace #1 (Xunit.Sdk.TestClassException) -----
----- Inner Stack Trace #2 (Xunit.Sdk.TestClassException) -----
Expected Behavior
No response
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
7.0.102
Anything else?
No response
Metadata
Metadata
Assignees
Labels
No labels