Прочитайте значения параметров json приложения в.NET Core Test Project
Моему веб-приложению нужно прочитать ключи Document 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);
}
Я ищу способы прочитать значения ключа в тестовом проекте.
4 ответа
Это основано на публикации в блоге " Использование файлов конфигурации в проектах модульного тестирования.NET Core" (написано для.NET Core 1.0).
Создайте (или скопируйте) файл appsettings.test.json в корневом каталоге тестового проекта интеграции и в свойствах укажите "Создать действие" в качестве содержимого и "Скопировать, если новее" в выходной каталог. Обратите внимание, что лучше иметь имя файла (например,
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>();
Добавьте файл конфигурации
Сначала добавьте файл appconfig.json в тестовый проект интеграции.
Настройте файл appconfig.json для копирования в выходной каталог, обновив
Добавить пакет NuGet
- Microsoft.Extensions.Configuration.Json
Используйте конфигурацию в своих модульных тестах
[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"];
}
}
Решение Садерсона сработало для меня, когда изменилось, как показано ниже:
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
автоматически подать в каталог сборки:
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<None Include="..\MyProj\appsettings.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
Скопируйте 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>]
Аналогично ответу Артема, но с использованием потока:
Stream configStream =
Assembly.GetExecutingAssembly()
.GetManifestResourceStream("MyNamespace.AppName.Test.appsettings.test.json");
IConfigurationRoot config = new ConfigurationBuilder()
.AddJsonStream(configStream)
.AddEnvironmentVariables()
.Build();
Я предпочитаю читать конфигурацию из потока, а не из файла. Это дает большую гибкость, потому что вы можете создать легкую тестовую установку без фиксации нескольких файлов конфигурации 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();
}
}
В 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)
Честно говоря, если вы проводите модульное тестирование приложения, вы должны попытаться изолировать класс, который вы тестируете, от всех зависимостей, таких как вызов других классов, доступ к файловой системе, базе данных, сети и т. Д., Если вы не проводите интеграционное тестирование или функциональное тестирование.
При этом для модульного тестирования приложения вы, вероятно, захотите смоделировать эти значения из файла 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}";
}
Затем в своем проекте тестов вы можете создать такой класс модульных тестов.
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 для насмешек.
Если вы используете WebApplicationFactory
чтобы создать тестовый сервер для интеграционных тестов, и у вас уже есть способ получить значения конфигурации в контроллерах на стороне сервера (вы, вероятно, делаете!), тогда вы можете просто повторно использовать это (и получить любые другие внедренные элементы, которые вам нужны) в ваших интеграционных тестах следующим образом:
// 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
который использует (тестовый) сервер.