【问题标题】:ASP.NET Core UseSetting from integration test来自集成测试的 ASP.NET Core UseSetting
【发布时间】:2017-06-08 20:16:01
【问题描述】:

我有一个集成测试项目,在测试类中使用.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();
}

我现在想在我的实际项目的 Startup.cs 中检索该设置。我尝试这样做:

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

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

但这似乎返回null。

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

【问题讨论】:

    标签: c# asp.net testing asp.net-core integration-testing


    【解决方案1】:

    您可以只在测试项目中使用本地配置文件的地方注入 IConfigurationRoot。您会丢失默认的特定于环境的配置覆盖,这是新项目模板中的默认配置,但我个人无论如何都不会将它们用于配置管理(更喜欢未提交的 appsetting.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)));
    

    对于启动:

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

    编辑: 虽然这确实有效,但它似乎也打破了IOptionsSnapshot 配置注入在运行时识别配置文件更改的问题。我将留下这个答案,但也会继续挖掘更好的方法,而不是注入自定义服务来支持特定于测试/夹具的配置覆盖。

    【讨论】:

    • 作为另一种选择,请查看:github.com/aspnet/Hosting/issues/333
    • 好建议!前一天遇到Startup.ConfigureServices方法中条件逻辑的问题,同样解决:可以添加构造函数Startup(Dictionary&lt;string, string&gt;),手动创建Startup实例。
    【解决方案2】:

    每次测试设置

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

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

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

    WebHostBuilder.ConfigureServices 调用中注册一个模拟实例:

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

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

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

    全局设置

    要设置不变(跨所有测试)设置,请设置进程范围的环境变量而不是 UseSetting 调用:

    Environment.SetEnvironmentVariable("foo", "bar");
    
    var _server = new TestServer(new WebHostBuilder()
        .UseStartup<Startup>()
    );
    

    然后阅读:

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

    你需要添加环境变量提供者从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();
    }
    

    【讨论】:

    • 在这样的测试中使用环境变量会产生副作用,因为测试是并行运行的。多个 TestServer 实例将开始交叉设置。
    • @agartee 是的,它是全球性的,这就是需要环境变量的原因。每个测试设置也是可能的,我添加它来回答。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 2016-11-22
    相关资源
    最近更新 更多