ASP。净芯采用集成测试

时间:2021-04-18 07:32:15

I have an integration tests project that uses .UseSetting() in the test class, as follows:

我有一个集成测试项目,在测试类中使用.UseSetting(),如下所示:

public AccessTokenRetrieval() : base(nameof(AccessTokenRetrieval))
{
    var connectionString = GetConnectionString();
    var dbSettings = new DbSettings(connectionString);
    _userGroupRepository = new UserGroupRepository(dbSettings);
    _roleRepository = new RoleRepository(dbSettings);
    _userRepository = new UserRepository(dbSettings);

    _server = new TestServer(new WebHostBuilder()
        .UseStartup<Startup>()
        .UseEnvironment("IntegrationTest")
        .UseSetting("IntegrationTestConnString", dbSettings.IdentityServerConnectionString));
    _handler = _server.CreateHandler();
    _client = _server.CreateClient();
}

I would now like to retrieve that setting in the Startup.cs of my actual project. I attempted to do so using:

现在我想在启动时检索该设置。实际项目的cs。我试图这样做:

public void ConfigureIntegrationTestServices(IServiceCollection services)
{
    var connectionString = Configuration.GetValue<string>("IntegrationTestConnString");

    BuildIdentityServerTests(services, connectionString);
    AddCoreServices(services, connectionString);
}

but that seems to return null.

但这似乎返回了null。

What is the proper way to retrieve this setting?

检索此设置的正确方法是什么?

2 个解决方案

#1


2  

Per-test setting

To pass a setting into a particular TestHost instance, you could use ConfigureServices call and override default setting registration.

要将设置传递到特定的TestHost实例,可以使用ConfigureServices调用并覆盖默认设置注册。

First of all, register your default DbSettings instance in Startup.ConfigureServices method. It's mandatory to use TryAll call:

首先,在Startup中注册默认的DbSettings实例。ConfigureServices方法。必须使用TryAll call:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.TryAddSingleton(new DbSettings(...));
    }
}

Register a mocked instance in WebHostBuilder.ConfigureServices call:

在WebHostBuilder中注册一个模拟实例。ConfigureServices电话:

_server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>()
    .ConfigureServices(services =>
        {
            services.AddSingleton(new DbSettings(...));
        }
    );

When you try to resolve a DbSettings in the application code, you will get a mocked instance. Because WebHostBuilder.ConfigureServices is executed first and TryAdd call prevents to register a default instance.

当您尝试在应用程序代码中解析DbSettings时,您将得到一个模拟的实例。因为WebHostBuilder。首先执行ConfigureServices, TryAdd调用将阻止注册一个默认实例。

This hint allows to replace any DI dependency you registered.

这个提示允许替换您注册的任何DI依赖项。

Global setting

To set an invariant (accross all tests) setting, set an process-scoped environment variable instead of UseSetting call:

要设置不变量(包括所有测试)设置,请设置流程范围内的环境变量,而不是usestting调用:

Environment.SetEnvironmentVariable("foo", "bar");

var _server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>()
);

Then read it:

然后读:

public void ConfigureServices(IServiceCollection services)
{
    string setting1 = Configuration["foo"];
    string setting2 = Environment.GetEnvironmentVariable("foo");
}

You need to add environment variable provider to read variables from Configuration:

您需要添加环境变量提供程序来从配置中读取变量:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)

        //this config provider is mandatory to read env vars from Configuration
        .AddEnvironmentVariables();

    Configuration = builder.Build();
}

#2


1  

You could just inject the IConfigurationRoot where you could just use a local config file in the test project. You'd lose the default environment-specific config overrides that are the default in the new project template, but I personally don't use those for configuration management anyway (preferring non-committed appsetting.local.json instead which can be unique to developers and to the CI server).

您只需注入icon具象根,在那里您可以在测试项目中使用本地配置文件。您将丢失新项目模板中默认的特定于环境的默认配置重写,但我个人不会将它们用于配置管理(更喜欢不提交的appsett.net .local)。而json可以是开发人员和CI服务器独有的)。

var configuration = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory)
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile("appsettings.local.json", optional: true, reloadOnChange: true)
    .AddInMemoryCollection(new Dictionary<string, string>
    {
        {"myConfig:setting1", "value1"},
        {"myConfig:setting2", "value2"}
    })
    .Build();

var server = new TestServer(new WebHostBuilder()
    .UseUrls("http://localhost:5001")
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseStartup<Startup>()
    .ConfigureServices(services => services.AddSingleton(configuration)));

And for Startup:

和启动:

public class Startup
{
    public Startup(IConfigurationRoot configuration)
    {
        this.Configuration = configuration;
    }

    ...
}

Edit: While this does work, it also seems to break IOptionsSnapshot configuration injections from recognizing config file changes at run-time. I'm going to leave this answer, but will also keep digging for better way without injecting a custom service just to support test/fixture-specific config overrides.

编辑:虽然这是可行的,但它似乎也会在运行时从识别配置文件更改中中断IOptionsSnapshot配置。我将留下这个答案,但也将继续挖掘更好的方法,而不注入自定义服务来支持特定于测试/修复的配置重写。

#1


2  

Per-test setting

To pass a setting into a particular TestHost instance, you could use ConfigureServices call and override default setting registration.

要将设置传递到特定的TestHost实例,可以使用ConfigureServices调用并覆盖默认设置注册。

First of all, register your default DbSettings instance in Startup.ConfigureServices method. It's mandatory to use TryAll call:

首先,在Startup中注册默认的DbSettings实例。ConfigureServices方法。必须使用TryAll call:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.TryAddSingleton(new DbSettings(...));
    }
}

Register a mocked instance in WebHostBuilder.ConfigureServices call:

在WebHostBuilder中注册一个模拟实例。ConfigureServices电话:

_server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>()
    .ConfigureServices(services =>
        {
            services.AddSingleton(new DbSettings(...));
        }
    );

When you try to resolve a DbSettings in the application code, you will get a mocked instance. Because WebHostBuilder.ConfigureServices is executed first and TryAdd call prevents to register a default instance.

当您尝试在应用程序代码中解析DbSettings时,您将得到一个模拟的实例。因为WebHostBuilder。首先执行ConfigureServices, TryAdd调用将阻止注册一个默认实例。

This hint allows to replace any DI dependency you registered.

这个提示允许替换您注册的任何DI依赖项。

Global setting

To set an invariant (accross all tests) setting, set an process-scoped environment variable instead of UseSetting call:

要设置不变量(包括所有测试)设置,请设置流程范围内的环境变量,而不是usestting调用:

Environment.SetEnvironmentVariable("foo", "bar");

var _server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>()
);

Then read it:

然后读:

public void ConfigureServices(IServiceCollection services)
{
    string setting1 = Configuration["foo"];
    string setting2 = Environment.GetEnvironmentVariable("foo");
}

You need to add environment variable provider to read variables from Configuration:

您需要添加环境变量提供程序来从配置中读取变量:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)

        //this config provider is mandatory to read env vars from Configuration
        .AddEnvironmentVariables();

    Configuration = builder.Build();
}

#2


1  

You could just inject the IConfigurationRoot where you could just use a local config file in the test project. You'd lose the default environment-specific config overrides that are the default in the new project template, but I personally don't use those for configuration management anyway (preferring non-committed appsetting.local.json instead which can be unique to developers and to the CI server).

您只需注入icon具象根,在那里您可以在测试项目中使用本地配置文件。您将丢失新项目模板中默认的特定于环境的默认配置重写,但我个人不会将它们用于配置管理(更喜欢不提交的appsett.net .local)。而json可以是开发人员和CI服务器独有的)。

var configuration = new ConfigurationBuilder()
    .SetBasePath(AppContext.BaseDirectory)
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile("appsettings.local.json", optional: true, reloadOnChange: true)
    .AddInMemoryCollection(new Dictionary<string, string>
    {
        {"myConfig:setting1", "value1"},
        {"myConfig:setting2", "value2"}
    })
    .Build();

var server = new TestServer(new WebHostBuilder()
    .UseUrls("http://localhost:5001")
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseStartup<Startup>()
    .ConfigureServices(services => services.AddSingleton(configuration)));

And for Startup:

和启动:

public class Startup
{
    public Startup(IConfigurationRoot configuration)
    {
        this.Configuration = configuration;
    }

    ...
}

Edit: While this does work, it also seems to break IOptionsSnapshot configuration injections from recognizing config file changes at run-time. I'm going to leave this answer, but will also keep digging for better way without injecting a custom service just to support test/fixture-specific config overrides.

编辑:虽然这是可行的,但它似乎也会在运行时从识别配置文件更改中中断IOptionsSnapshot配置。我将留下这个答案,但也将继续挖掘更好的方法,而不注入自定义服务来支持特定于测试/修复的配置重写。