I'm writing integration tests in my .NET Web API. I'm using XUnit for this. I am using factory and collection. And everything works as expected. I run factory there I have used PostgreSql database using test container. I transfer the connection string to the application, where the migration starts. Everything goes through and it's great.
However, the moment I added a second factory and started up the PostgreSql factory again it still worked, but all of a sudden it started happening that when I run all the tests with a different factory it stumbles and the tests crash on the following error.
Message:
Npgsql.PostgresException : 23505: duplicate key value violates unique constraint "pg_type_typname_nsp_index"DETAIL: Detail redacted as it may contain sensitive data. Specify 'Include Error Detail' in the connection string to include this information.
Stack Trace:
NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
IValueTaskSource<TResult>.GetResult(Int16 token)
NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
NpgsqlDataReader.NextResult()
NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
NpgsqlCommand.ExecuteNonQuery(Boolean async, CancellationToken cancellationToken)
NpgsqlCommand.ExecuteNonQuery()
RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
<13 more frames...>
WebApplicationFactory`1.CreateHost(IHostBuilder builder)
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()
It looks to me like the tests are connecting to the wrong database. I tried setting database names, ports etc but nothing helped. Of course the error doesn't pop up every time the tests run, but only occasionally. Unfortunately I couldn't find much information on the internet and it seems to me that I must be doing something extremely wrong.
FullSetupWriteFactory
(second factory "Read" looks the same)
public class FullSetupWriteFactory : WebApplicationFactory<Program>, IAsyncLifetime
{
private readonly PostgreSqlContainer _postgresContainer;
public FullSetupWriteFactory()
{
var dbName = $"db_{Guid.NewGuid():N}";
_postgresContainer = new PostgreSqlBuilder()
.WithDatabase(dbName)
.Build();
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
System.Environment.SetEnvironmentVariable("ConnectionStrings__DbConnection", _postgresContainer.GetConnectionString());
builder.ConfigureServices(services =>
{
});
}
public async Task InitializeAsync()
{
await _postgresContainer.StartAsync();
}
public new async Task DisposeAsync()
{
await _postgresContainer.StopAsync();
await _postgresContainer.DisposeAsync();
}
}
FullSetupWriteCollection
:
[CollectionDefinition(Name)]
public class FullSetupWriteCollection : ICollectionFixture<FullSetupWriteFactory>
{
public const string Name = "FullSetupWrite";
}
OrderControllerTest
:
[Collection(FullSetupWriteCollection.Name)]
public partial class OrderControllerTest
{
Test1....
Test2....
}
ItemControllerTest
:
[Collection(FullSetupReadCollection.Name)]
public partial class OrderControllerTest
{
Test1....
Test2....
}
I run the migration in Program.cs
with a simple command.
_dbContext.Database.Migrate();
Thank you very much in advance
Since there is no full Minimal, Reproducible Example (and runnable without too much setup) provided I will do a bit of guess work, but the following approach to handling connection string seems wrong:
System.Environment.SetEnvironmentVariable("ConnectionStrings__DbConnection", _postgresContainer.GetConnectionString())
Imagine two factories starting at the same time and running this line simultaneously - your test run will end with only one connection string in the environment variable, so all instances of your simultaneously running hosts can end up with the same connection string hence the errors.
As far as I can see you are using EF Core to handle your data access, and in such cases usual approach is to remove some EF Core stuff from the DI container in the ConfigureWebHost
call and register context back. For more info see