8

I am currently writing an integration test to test my APIs using WebApplicationFactory.

I have created a CustomWebApplicationFactory. I want to read the default appsettings.json that is found in the main web project. I know this can be achieved as below:

private static readonly IConfigurationRoot _configuration; // Global

// Inside Constructor
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", true, true)

 _configuration = builder.Build();

// To get connectionstring

var connStr = _configuration.GetConnectionString("DefaultConnection");

In my case, I want to use appsettings.json by default. Is there a way I can retrieve the connectionstring by reading appsettings.json from main Web project without defining the AddJsonFile codes in the constructor?

avi
  • 371
  • 1
  • 7
  • 20

3 Answers3

3

You can do it this way (code below). I.e. intercept the builder and build the config the same way the service does.

public class MyApiServiceWrapper : WebApplicationFactory<Api.Startup>
{
    private IConfiguration _configuration;

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureAppConfiguration((context, conf) =>
        {
            // expand default config with settings designed for Integration Tests
            conf.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "appsettings.Integration.json"));
            conf.AddEnvironmentVariables();

            // here we can "compile" the settings. Api.Setup will do the same, it doesn't matter.
            _configuration = conf.Build();
        });

        builder.ConfigureTestServices(srv =>
        {
            // here you can change some internal services of the Api.Startup
            // and change them to mocks
        });

        base.ConfigureWebHost(builder);
    }

    public TConfig GetConfiguration<TConfig>()
    {
        // start my service to get the config built...
        this.CreateClient(); 
        // ... and then cast it to my type
        return _configuratio.Get<TConfig>();
    }
}
andrew.fox
  • 7,435
  • 5
  • 52
  • 75
0

For the following setup:

public class Fixtures
{
    public readonly WebApplicationFactory<WebApplication1.Program> Factory { get; }
    
    public Fixtures()
    {
        Factory = new WebApplicationFactory<Startup>().WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                services.Configure<YourSettings>(settings =>
                {
                    settings.Setting1 = "OverrideSetting1"
                });
            });
        });
    }
}

If you use Options pattern, you could try requesting your settings from IServiceProvider using the GetService<T> method:

public class Test
{
    private readonly YourSettings _settings;
    
    public Test(Fixtures fixtures)
    {
        var settingsOptions = fixtures.Factory.Services.GetService<IOptions<YourSettings>>();
        _settings = settingsOptions?.Value;
    }
}
Oleg Vitols
  • 71
  • 2
  • 3
0

Since I inject the WebApplicationFactory<Program> into my integration test classes, I use the following:

public class MyIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
  private readonly WebApplicationFactory<Program> _app;
  private readonly IConfiguration? _config;
  
  public MyIntegrationTests(WebApplicationFactory<Program> app) 
  {
    _app = app;
    _config = app.Services.GetService<IConfiguration>();
  }

}
fix
  • 1,425
  • 16
  • 27