2

I have built a custom web application Factory to run a in memory test server for integration tests. Instead of using in memory database, we are trying to use a sql database.

My problem is that the connection string is changing for each environment. We have several appsettings{envName}.json files with the connection string. So, I need to find a solution for getting the env variable. These are my tries:

public class CustomWebApplicationSQLServerFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            var serviceProvider = new ServiceCollection()
                .AddEntityFrameworkSqlServer()
                .BuildServiceProvider();

            var env = serviceProvider.GetService<IHostingEnvironment>();

            Configuration = new ConfigurationBuilder()
                .SetBasePath(AppContext.BaseDirectory)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables()
                .Build();

            var defaultConnection = Configuration.GetConnectionString("DefaultConnection");
            var connectionString = string.Format(defaultConnection, "TestSampleOrder_" + Guid.NewGuid().ToString());

            services.AddDbContext<SampleOrderContext>(options =>
            {
                options.UseSqlServer(connectionString);
                options.UseInternalServiceProvider(serviceProvider);
            });

            var sp = services.BuildServiceProvider();

            using (var scope = sp.CreateScope())
            {
                var scopedServices = scope.ServiceProvider;

                var context = scopedServices.GetRequiredService<SampleOrderContext>();

                DbInitializer.InitializeDbForTests(context);
            }
        });
    }

Also I have added in my test Project a launchSettings.json file. In that file, under my test Project name, I have added "ASPNETCORE_ENVIRONMENT": "AnyValue". So, I can't understand why env = null. After doing more tests, env.EnvironmentName = "Development", and application name and path are the main Project. Why? "Development" Word is NOT set in the hole solution.

I tried also replace the env line for this one:

var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

If I set a Windows variable, I can get the value using that, but I need to understand how can I set the value of the variable in my launchSettings file.

Another thing I have tried is this:

var serviceProvider = services.BuildServiceProvider();

But I really don't understand the difference.

Can anyone please help me to understand how this is working, what is the best way to get the env variable and what is the difference between using services.BuildServiceProvider() and new ServiceCollection()?

Thanks a lot.

Acel
  • 143
  • 1
  • 3
  • 11
  • ARe you *sure* you need to test that? The only way for `Environment.GetEnvironmentVariable` to fail is if .NET Core itself is broken. `envName` is just a string. It can come from anywhere - a call to `Environment.GetEnvironmentVariable`, a command-line argument or a parameter passed to your method. – Panagiotis Kanavos May 28 '19 at 11:37
  • 2
    In any case, `var env = serviceProvider.GetService();` means that the `IHostingEnvironment` class is itself a dependency. You can register your own `IHostingEnvironment` implementation in your test that returns hard-coded environment names – Panagiotis Kanavos May 28 '19 at 11:39
  • How do you run this web application? dotnet cli or visual studio? – Vivek Natarajan May 28 '19 at 11:40
  • I'm using visual studio for run it – Acel May 28 '19 at 11:49
  • I have edited my question. My env variable have "development" data. I have no environment variable in Windows and also no entries in any launchSettings.json with "Development" set. In fact, even doing a whole search in the solution, "Development" Word is not found in it. – Acel May 29 '19 at 09:22

1 Answers1

0

Perhaps this question could provide some insight.

That being said, the "simplest" way to go about testing with configuration is to abstract what you need. Maybe you could build an adapter that gives you the environment name, e.g.:

public interface IApplicationConfiguration
{
    string GetEnvironmentName();
}

public class ApplicationConfiguration
{
    private IHostingEnvironment _hostingConfiguration;

    public ApplicationConfiguration(IHostingEnvironment hostingConfiguration)
    {
        _hostingConfiguration = hostingConfiguration;
    }

    public string GetEnvironmentName()
    {
        return _hostingConfiguration.EnvironmentName;
    }
}

You could solve it using other options but mocking these type of settings can be quite useful.

Eben Roux
  • 12,983
  • 2
  • 27
  • 48