What configuration precedence rules apply when overriding connection strings in ASP.NET Core integration tests using WebApplicationFactory?
0 reputation · 23 Jun 2024, 08:11 UTC
0 reputation · 23 Jun 2024, 08:11 UTC
The goal is to configure ASP.NET Core integration tests so that they never read production secrets while still exercising the same configuration binding logic used in production.
When using WebApplicationFactory to create a test host, developers can override settings via environment variables, user‑secrets, or testcontainers, but it is not clear which source takes precedence when the same key is supplied by more than one mechanism, nor whether the test host’s configuration builder might inadvertently fall back to a user‑secret value.
Which configuration source wins when both an environment variable and a user‑secret are defined for the same key in a test host built with WebApplicationFactory? Does setting a connection string through an environment variable guarantee that any user‑secret value for that key is ignored? Can testcontainers be combined with environment‑variable overrides without risking that the container’s internal configuration overrides the test host’s settings?
30275 reputation · 23 Jun 2024, 12:37 UTC
Which source wins when both an environment variable and a user secret are defined for the same key? The user secret wins. In the default configuration builder order, user secrets are added after environment variables, so they override environment-variable values for the same key.
Does setting a connection string through an environment variable guarantee that any user-secret value for that key is ignored? No. Because user secrets load later in the default pipeline, a user secret with the same key will take precedence over the environment variable.
Can testcontainers be combined with environment-variable overrides without risking that the container's internal configuration overrides the test host's settings? Yes, but only if you inject the testcontainer connection string via ConfigureAppConfiguration (e.g., AddInMemoryCollection) after the default sources. Adding it as an environment variable alone is not sufficient because a user secret would still win.
ASP.NET Core builds configuration in this sequence (later sources override earlier ones):
appsettings.jsonappsettings.{Environment}.jsonEnvironment.IsDevelopment())WebApplicationFactory preserves this order. When you call builder.ConfigureAppConfiguration in a test, your custom source is appended after all the defaults, giving it the highest precedence for that test host.
To ensure a testcontainer or any test-specific connection string dominates user secrets and environment variables, add it through ConfigureAppConfiguration:
var factory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((context, config) =
{
config.AddInMemoryCollection(new Dictionary<string, string>
{
["ConnectionStrings:MyDb"] = testContainerConnectionString
});
});
});
This in-memory collection is added last, so it overrides any user secret or environment variable with the same key.
WebApplicationFactory<Program>.ConnectionStrings:MyDb=UserSecretValue in Development.ConnectionStrings:MyDb=EnvVarValue before building the factory.IConfiguration["ConnectionStrings:MyDb"] should return UserSecretValue.AddInMemoryCollection override shown above; the value should be testContainerConnectionString.Are your integration tests running with ASPNETCORE_ENVIRONMENT=Development (the default for WebApplicationFactory)? If they run under a different environment name, user secrets are not loaded at all, and the environment variable would win by default.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.