读取.NET 核心测试项目中的 appsetsjson 值

我的 Web 应用程序需要从 appsetings.json 文件中读取 Document DB 密钥。我已经用键名创建了一个类,并将 ConfigureServices()中的 Config 部分读取为:

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


Configuration = builder.Build();
}


public IConfigurationRoot Configuration { get; }


public void ConfigureServices(IServiceCollection services) {
services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddSession();
Helpers.GetConfigurationSettings(services, Configuration);
DIBuilder.AddDependency(services, Configuration);
}

我正在寻找在测试项目中读取键值的方法。

122548 次浏览

在测试项目的 project.json中,添加以下依赖项:

"dependencies": {
"xunit": "2.2.0-beta2-build3300",
"Microsoft.AspNetCore.TestHost": "1.0.0",
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"BancoSentencas": "1.0.0-*"
},

BancoSentencas是我想测试的项目。其他包来自 xUnit 和 TestHost,它们将成为我们的内存服务器。

还要包含 appsetings.json 的构建选项:

"buildOptions": {
"copyToOutput": {
"include": [ "appsettings.Development.json" ]
}
}

In my test project, I have the following test class:

  public class ClasseControllerTeste : IClassFixture<TestServerFixture> {


public ClasseControllerTeste(TestServerFixture fixture) {
Fixture = fixture;
}


protected TestServerFixture Fixture { get; private set; }




[Fact]
public async void TestarRecuperarClassePorId() {
using(var client = Fixture.Client) {
var request = await Fixture.MyHttpRequestMessage(HttpMethod.Get, "/api/classe/1436");
var response = await client.SendAsync(request);
string obj = await response.Content.ReadAsStringAsync();
ClasseModel classe = JsonConvert.DeserializeObject<ClasseModel>(obj);
Assert.NotNull(classe);
Assert.Equal(1436, classe.Id);
}
}
}

我还有一个 TestServerFixture 类,它将配置内存中的服务器:

  public class TestServerFixture : IDisposable {
private TestServer testServer;
protected TestServer TestServer {
get {
if (testServer == null)
testServer = new TestServer(new WebHostBuilder().UseEnvironment("Development").UseStartup<Startup>());
return testServer;
}
}


protected SetCookieHeaderValue Cookie { get; set; }


public HttpClient Client {
get {
return TestServer.CreateClient();
}
}


public async Task<HttpRequestMessage> MyHttpRequestMessage(HttpMethod method, string requestUri) {
...
login stuff...
...
Cookie = SetCookieHeaderValue.Parse(response.Headers.GetValues("Set-Cookie").First());


var request = new HttpRequestMessage(method, requestUri);


request.Headers.Add("Cookie", new CookieHeaderValue(Cookie.Name, Cookie.Value).ToString());
request.Headers.Accept.ParseAdd("text/xml");
request.Headers.AcceptCharset.ParseAdd("utf-8");
return request;
}


public void Dispose() {
if (testServer != null) {
testServer.Dispose();
testServer = null;
}
}
}

我就是这样测试我的项目的。我使用来自主项目的 Startup.cs,并从我的测试项目(appsets)中的 appsetings.json 创建一个副本。Development.json)

Honestly, if you are 单元测试 an application, you should try to isolate the class you are testing from all dependencies, like calling other classes, accessing file system, database, network etc. Unless you are doing integration testing or functional testing.

Having that said, to unit test the application, you probably want to 嘲笑 these values from your appsettings.json file, and just test your logic.

所以你的 appsettings.json应该是这样的。

"DocumentDb": {
"Key": "key1"
}

然后创建一个设置类。

public class DocumentDbSettings
{
public string Key { get; set; }
}

然后在 ConfigureServices()方法中注册它。

services.Configure<DocumentDbSettings>(Configuration.GetSection("DocumentDb"));

然后,例如,您的控制器/类可以看起来像这样。

// ...
private readonly DocumentDbSettings _settings;


public HomeController(IOptions<DocumentDbSettings> settings)
{
_settings = settings.Value;
}
// ...
public string TestMe()
{
return $"processed_{_settings.Key}";
}

然后在您的测试项目中,您可以创建这样的单元测试类。

public class HomeControllerTests
{
[Fact]
public void TestMe_KeyShouldBeEqual_WhenKeyIsKey1()
{
// Arrange
const string expectedValue = "processed_key1";
var configMock = Substitute.For<IOptions<DocumentDbSettings>>();
configMock.Value.Returns(new DocumentDbSettings
{
Key = "key1" // Mocking the value from your config
});


var c = new HomeController(configMock);


// Act
var result = c.TestMe();


// Assert
Assert.Equal(expectedValue, result);
}
}

我使用 NSubstitutev2.0.0-rc 进行嘲讽。

Copy the appSettings.json to your Test project root directory and mark its property as Content and 如果更新,请复制.

var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
ConfigurationManager.Configuration = builder.Build();

ConfigurationManager是一个类,它具有一个静态属性 Configuration。这样,整个应用程序就可以作为 ConfigurationManager.Configuration[<key>]访问它

这是基于博客文章 使用.NET 核心单元测试项目中的配置文件 (为.NET Core 1.0编写)。

  1. 在 Integration 测试项目根目录中创建(或复制) appsetings.test.json,并在属性中将“ Build Action”指定为 Content,将“ Copy if new”指定为 Output Directory。请注意,文件名(例如 appsettings.test.json)最好与正常的 appsettings.json不同,因为如果使用相同的名称,来自主项目的文件可能会覆盖来自测试项目的文件。

  2. 如果尚未包含 JSON 配置文件 NuGet 包(Microsoft.Extensions.Configuration. JSON) ,则包含它。

  3. 在测试项目中创建一个方法,

     public static IConfiguration InitConfiguration()
    {
    var config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.test.json")
    .AddEnvironmentVariables()
    .Build();
    return config;
    }
    

如果您希望传递一些不希望存储在 appsetings.test.json 中的秘密,那么 AddEnvironment Variables (在 @ RickStrahl 博客中建议使用)非常有用

  1. Use the configuration as usual

     var config = InitConfiguration();
    var clientId = config["CLIENT_ID"]
    

顺便说一句: 你也可能对将配置读入 集成测试与 IOptions < > 在.NET Core 中中描述的 IOptions 类感兴趣:

var options = config.Get<MySettings>();

Suderson 的解决方案在修改如下时对我有效:

var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();


IConfiguration config = builder.Build();


//Now, You can use config.GetSection(key) to get the config entries

对于 ASP.NET Core 2.x 项目,自动将 appsettings.json文件复制到 build 目录:

<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<None Include="..\MyProj\appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>

如果您正在使用 WebApplicationFactory to create a test server for integration tests,并且已经有办法在服务器端控制器中获取配置值(您可能已经有了!),然后您可以在您的集成测试中重用它(并获取您需要的任何其他注入项) ,如下所示:

// Your test fixtures would be subclasses of this
public class IntegrationTestBase : IDisposable
{
private readonly WebApplicationFactory<Startup> _factory;
protected readonly HttpClient _client;


// The same config class which would be injected into your server-side controllers
protected readonly IMyConfigService _myConfigService;


// Constructor (called by subclasses)
protected IntegrationTestBase()
{
// this can refer to the actual live Startup class!
_factory = new WebApplicationFactory<Startup>();
_client = _factory.CreateClient();


// fetch some useful objects from the injection service
_myConfigService = (IMyConfigService)_factory.Server.Host.Services.GetService(typeof(IMyConfigService));
}


public virtual void Dispose()
{
_client.Dispose();
_factory.Dispose();
}
}

注意,在这种情况下,您不需要复制到 appsettings.json上,您将自动使用(测试)服务器正在使用的相同 appsettings.json

添加配置文件

首先,向 Integration 测试项目添加 appconfig.json 文件

Configure the appconfig.json file to be copied to the output 通过更新

目录

enter image description here

添加 NuGet 包

  • 微软。扩展。配置。 Json

Use the configuration in your unit tests

[TestClass]
public class IntegrationTests
{
public IntegrationTests()
{
var config = new ConfigurationBuilder().AddJsonFile("appconfig.json").Build();
        

_numberOfPumps = Convert.ToInt32(config["NumberOfPumps"]);


_numberOfMessages = Convert.ToInt32(config["NumberOfMessages"]);


_databaseUrl = config["DatabaseUrlAddress"];
}
}

我更喜欢从流中而不是从文件中读取配置。这带来了更大的灵活性,因为您可以创建轻量级的测试设置,而无需提交多个 json 配置文件:

public static class ConfigurationHelper
{
public static IConfigurationRoot GetConfiguration()
{
byte[] byteArray = Encoding.ASCII.GetBytes("{\"Root\":{\"Section\": { ... }}");
using var stream = new MemoryStream(byteArray);
return new ConfigurationBuilder()
.AddJsonStream(stream)
.Build();
}
}

阿提姆回答类似,但使用嵌入式资源(作为流) :

Stream configStream =
Assembly.GetExecutingAssembly()
.GetManifestResourceStream("MyNamespace.AppName.Test.appsettings.test.json");


IConfigurationRoot config = new ConfigurationBuilder()
.AddJsonStream(configStream)
.AddEnvironmentVariables()
.Build();

enter image description here