Чтение значений jset-значений appsettings в .NET Core Test Project
Моему веб-приложению необходимо прочитать ключи документа DB из файла appsettings.json. Я создал класс с именами ключей и прочитал раздел Config в ConfigureaServices()
как:
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);
}
Я ищу способы прочитать значения ключа в тестовом проекте.
Ответы
Ответ 1
Это основано на публикации в блоге " Использование файлов конфигурации в проектах модульного тестирования .NET Core" (написано для .NET Core 1.0).
-
Создайте (или скопируйте) appsettings.test.json в корневом каталоге тестового проекта интеграции, а в свойствах укажите "Build Action" в качестве содержимого и "Копировать, если новее" в выходной каталог. Обратите внимание, что лучше иметь имя файла (например, appsettings.test.json
) отличным от обычного appsettings.json
, поскольку возможно, что файл из основного проекта переопределит файл из тестового проекта, если будет использоваться то же имя.
-
Включите пакет NuGet файла конфигурации JSON (Microsoft.Extensions.Configuration.Json), если он еще не включен.
-
В тестовом проекте создайте метод,
public static IConfiguration InitConfiguration()
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.test.json")
.Build();
return config;
}
-
Используйте конфигурацию как обычно
var config = InitConfiguration();
var clientId = config["CLIENT_ID"]
Кстати, вам также может быть интересно прочитать конфигурацию в классе IOptions, как описано в тесте интеграции с IOptions <> в .NET Core:
var options = config.Get<MySettings>();
Ответ 2
Честно говоря, если вы тестируете приложение, вы должны попытаться изолировать класс, который вы тестируете, от всех зависимостей, таких как вызов других классов, доступ к файловой системе, базе данных, сети и т.д. Если вы не проводите интеграционное тестирование или функциональное тестирование.
Сказав, что в unit test приложение, вы, вероятно, захотите высмеять эти значения из своего файла appsettings.json и просто проверьте свою логику.
Итак, ваш 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}";
}
Затем в проекте тестов вы можете создать такой класс unit test.
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);
}
}
Я использовал NSubstitute v2.0.0-rc для насмешек.
Ответ 3
В 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, которые будут нашим сервером на сервере.
Включите также эту возможность сборки для appsettings.json:
"buildOptions": {
"copyToOutput": {
"include": [ "appsettings.Development.json" ]
}
}
В моем тестовом проекте у меня есть следующий тестовый класс:
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 из основного проекта, и я создаю копию из appsettings.json в своем тестовом проекте (appsettings.Development.json)
Ответ 4
Решение 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
Ответ 5
Скопируйте appSettings.json
в корневой каталог вашего тестового проекта и отметьте его свойство как Content and Copy, если оно более новое.
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
ConfigurationManager.Configuration = builder.Build();
ConfigurationManager
является классом и имеет статическое свойство Configuration
. Таким образом, все приложение может просто получить к нему доступ как ConfigurationManager.Configuration[<key>]
Ответ 6
Для проектов ASP.NET Core 2.x скопируйте файл appsettings.json
каталог сборки автоматически:
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<None Include="..\MyProj\appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
Ответ 7
Если вы используете WebApplicationFactory
для создания тестового сервера для интеграционных тестов, и у вас уже есть способ получить значения конфигурации в ваших контроллерах на стороне сервера (вы, вероятно, делаете это!), То вы можете просто повторно использовать это (и получить на любом другие необходимые элементы) в ваших интеграционных тестах, а именно:
// Your test fixtures would be subclasses of this
public class IntegrationTestBase
{
// 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));
}
}
Обратите внимание, что в этом случае вам не нужно копировать appsettings.json
, вы автоматически используете тот же appsettings.json
который использует (тестовый) сервер.