ASP.NET Core UseSetting来自集成测试
我有一个集成测试项目,在测试类中使用.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() .UseEnvironment("IntegrationTest") .UseSetting("IntegrationTestConnString", dbSettings.IdentityServerConnectionString)); _handler = _server.CreateHandler(); _client = _server.CreateClient(); }
我现在想在我的实际项目的Startup.cs中检索该设置。 我试图这样做:
public void ConfigureIntegrationTestServices(IServiceCollection services) { var connectionString = Configuration.GetValue("IntegrationTestConnString"); BuildIdentityServerTests(services, connectionString); AddCoreServices(services, connectionString); }
但这似乎返回null。
检索此设置的正确方法是什么?
每次测试设置
要将设置传递到特定的TestHost
实例,您可以使用ConfigureServices
调用并覆盖默认设置注册。
首先,在Startup.ConfigureServices
方法中注册默认的DbSettings
实例。 必须使用TryAll
调用:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.TryAddSingleton(new DbSettings(...)); } }
在WebHostBuilder.ConfigureServices
调用中注册一个WebHostBuilder.ConfigureServices
实例:
_server = new TestServer(new WebHostBuilder() .UseStartup() .ConfigureServices(services => { services.AddSingleton(new DbSettings(...)); } );
当您尝试在应用程序代码中解析DbSettings
时,您将获得一个DbSettings
的实例。 因为WebHostBuilder.ConfigureServices
执行WebHostBuilder.ConfigureServices
并且WebHostBuilder.ConfigureServices
调用阻止注册默认实例。
此提示允许替换您注册的任何DI依赖项。
全局设置
要设置不变量(包含所有测试)设置,请设置进程范围的环境变量而不是UseSetting
调用:
Environment.SetEnvironmentVariable("foo", "bar"); var _server = new TestServer(new WebHostBuilder() .UseStartup() );
然后阅读:
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(); }
你可以只注入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 { {"myConfig:setting1", "value1"}, {"myConfig:setting2", "value2"} }) .Build(); var server = new TestServer(new WebHostBuilder() .UseUrls("http://localhost:5001") .UseContentRoot(Directory.GetCurrentDirectory()) .UseStartup() .ConfigureServices(services => services.AddSingleton(configuration)));
对于初创公司:
public class Startup { public Startup(IConfigurationRoot configuration) { this.Configuration = configuration; } ... }
编辑:虽然这确实有效,但它似乎也会破坏IOptionsSnapshot
配置注入,从而在运行时识别配置文件更改。 我将留下这个答案,但也会继续挖掘更好的方法而不注入自定义服务只是为了支持测试/特定于夹具的配置覆盖。