Test Overrides
CocoarTestConfiguration lets you replace or extend configuration in tests without touching real files, environment variables, or HTTP endpoints. It uses AsyncLocal<T> for isolation — each test gets its own configuration context, parallel-safe.
Replace vs Append
ReplaceConfiguration
Skips all original rules. Only your test rules execute:
using var _ = CocoarTestConfiguration.ReplaceConfiguration(rule => [
rule.For<DbConfig>().FromStatic(_ => new DbConfig
{
ConnectionString = "Server=localhost;Database=test"
})
]);
// ConfigManager now uses only the test ruleUse this when:
- Original providers would fail in the test environment (missing files, unreachable URLs)
- You want complete isolation from real configuration
AppendConfiguration
Original rules execute first, then your test rules overlay on top (last-write-wins merge):
using var _ = CocoarTestConfiguration.AppendConfiguration(rule => [
rule.For<AppSettings>().FromStatic(_ => new AppSettings
{
MaxRetries = 999
})
]);
// Original AppSettings rules run first, then test values merge over themUse this when:
- You only need to override specific values
- You want the rest of the configuration to behave normally
Secrets Override
Secrets setup is overridden independently from rules. You can combine it with either mode:
// Replace rules + allow plaintext secrets
using var _ = CocoarTestConfiguration
.ReplaceConfiguration(rule => [...])
.ReplaceSecretsSetup(s => s.AllowPlaintext());
// Only override secrets, keep original rules
using var _ = CocoarTestConfiguration
.ReplaceSecretsSetup(s => s.AllowPlaintext());AllowPlaintext() is the most common test override — it skips encryption so you can use plain JSON values in test configuration.
Setup Override ADV
You can also override the setup (DI registration customization) alongside rules:
using var _ = CocoarTestConfiguration.ReplaceConfiguration(
rules: rule => [
rule.For<AppSettings>().FromStatic(_ => new AppSettings { LogLevel = "Debug" })
],
setup: setup => [
setup.ConcreteType<AppSettings>().AsSingleton()
]);Disposal
The using pattern ensures cleanup. When the scope disposes, CocoarTestConfiguration.Clear() is called and the test context is removed from the AsyncLocal:
[Fact]
public async Task MyTest()
{
using var _ = CocoarTestConfiguration.ReplaceConfiguration(rule => [...]);
// Test code — configuration is overridden here
// ...
} // Automatically cleared, even on exceptionHow It Works
CocoarTestConfigurationstores aTestConfigurationContextin anAsyncLocal<T>- The context flows through
async/awaitchains automatically - When
ConfigManagerinitializes, it checksCocoarTestConfiguration.IsActive - If active, it uses the test rules (Replace or Append mode) instead of or in addition to the configured rules
- Each test's
AsyncLocalis isolated — parallel tests don't interfere