Meine Webanwendung muss die Dokument-DB-Schlüssel aus der Datei appsettings.json lesen. Ich habe eine Klasse mit den Schlüsselnamen erstellt und den Abschnitt Config ConfigureaServices()
wie folgt gelesen :
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);
}
Ich suche nach Möglichkeiten, die Schlüsselwerte im Testprojekt zu lesen.
c#
unit-testing
asp.net-core
appsettings
S.Siva
quelle
quelle
Antworten:
Dies basiert auf dem Blogbeitrag Verwenden von Konfigurationsdateien in .NET Core-Komponententestprojekten (geschrieben für .NET Core 1.0).
Erstellen (oder kopieren) Sie die Datei appsettings.test.json im Stammverzeichnis des Integrationstestprojekts und geben Sie in den Eigenschaften "Build Action" als Inhalt und "Copy if new" in das Ausgabeverzeichnis an. Beachten Sie, dass es besser ist, einen anderen Dateinamen (z. B.
appsettings.test.json
) als normal zu verwendenappsettings.json
, da möglicherweise eine Datei aus dem Hauptprojekt die Datei aus dem Testprojekt überschreibt, wenn derselbe Name verwendet wird.Fügen Sie das NuGet-Paket der JSON-Konfigurationsdatei (Microsoft.Extensions.Configuration.Json) hinzu, falls es noch nicht enthalten ist.
Erstellen Sie im Testprojekt eine Methode,
public static IConfiguration InitConfiguration() { var config = new ConfigurationBuilder() .AddJsonFile("appsettings.test.json") .Build(); return config; }
Verwenden Sie die Konfiguration wie gewohnt
var config = InitConfiguration(); var clientId = config["CLIENT_ID"]
Übrigens: Möglicherweise ist es auch interessant, die Konfiguration in die IOptions-Klasse einzulesen, wie im Integrationstest mit IOptions <> in .NET Core beschrieben :
var options = config.Get<MySettings>();
quelle
Fügen Sie die Konfigurationsdatei hinzu
Fügen Sie zunächst dem Integrationstestprojekt eine Datei appconfig.json hinzu
Konfigurieren Sie die Datei appconfig.json, die durch Aktualisierung in das Ausgabeverzeichnis kopiert werden soll
NuGet-Paket hinzufügen
Verwenden Sie die Konfiguration in Ihren 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"]; } }
quelle
Die Lösung von Suderson hat bei mir wie folgt funktioniert:
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
quelle
Kopieren Sie das
appSettings.json
in das Stammverzeichnis Ihres Testprojekts und markieren Sie dessen Eigenschaft als Inhalt und Kopieren, falls neu .var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddEnvironmentVariables(); ConfigurationManager.Configuration = builder.Build();
ConfigurationManager
ist eine Klasse und hat eine statische EigenschaftConfiguration
. Auf diese Weise kann die gesamte Anwendung einfach als darauf zugreifenConfigurationManager.Configuration[<key>]
quelle
Fügen
project.json
Sie im Testprojekt von Ihnen die folgenden Abhängigkeiten hinzu:"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
ist das Projekt, das ich testen möchte. Die anderen Pakete stammen von xUnit und dem TestHost, der unser In-Memory-Server sein wird.Fügen Sie auch diese Build-Option für die Datei appsettings.json hinzu:
"buildOptions": { "copyToOutput": { "include": [ "appsettings.Development.json" ] } }
In meinem Testprojekt habe ich folgende Testklasse:
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); } } }
Außerdem habe ich die TestServerFixture-Klasse, mit der der In-Memory-Server konfiguriert wird:
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; } } }
So teste ich mein Projekt. Ich verwende die Startup.cs aus dem Hauptprojekt und erstelle in meinem Testprojekt (appsettings.Development.json) eine Kopie aus appsettings.json.
quelle
Microsoft.AspNetCore.TestHost
Paket. Verwenden Sie xUnit? Ich werde meine Antwort bearbeiten und weitere Details bereitstellen.Ich lese die Konfiguration lieber aus einem Stream als aus einer Datei. Dies bietet mehr Flexibilität, da Sie ein leichtes Test-Setup erstellen können, ohne mehrere JSON-Konfigurationsdateien festzuschreiben:
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(); } }
quelle
Ähnlich wie bei Artem , jedoch mit einer eingebetteten Ressource (als Stream):
Stream configStream = Assembly.GetExecutingAssembly() .GetManifestResourceStream("MyNamespace.AppName.Test.appsettings.test.json"); IConfigurationRoot config = new ConfigurationBuilder() .AddJsonStream(configStream) .AddEnvironmentVariables() .Build();
quelle
Wenn Sie eine Anwendung auf Einheit testen , sollten Sie ehrlich gesagt versuchen, die zu testende Klasse von allen Abhängigkeiten zu isolieren, z. B. vom Aufrufen anderer Klassen, dem Zugriff auf Dateisystem, Datenbank, Netzwerk usw., es sei denn, Sie führen Integrationstests oder Funktionstests durch.
Um die Anwendung zu testen, möchten Sie diese Werte wahrscheinlich aus Ihrer Datei appsettings.json verspotten und einfach Ihre Logik testen.
Du
appsettings.json
würdest also so aussehen."DocumentDb": { "Key": "key1" }
Erstellen Sie dann eine Einstellungsklasse.
public class DocumentDbSettings { public string Key { get; set; } }
Dann registrieren Sie es in
ConfigureServices()
Methode.services.Configure<DocumentDbSettings>(Configuration.GetSection("DocumentDb"));
Dann könnte beispielsweise Ihr Controller / Ihre Klasse so aussehen.
// ... private readonly DocumentDbSettings _settings; public HomeController(IOptions<DocumentDbSettings> settings) { _settings = settings.Value; } // ... public string TestMe() { return $"processed_{_settings.Key}"; }
Dann können Sie in Ihrem Testprojekt eine solche Unit-Test-Klasse erstellen.
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); } }
Ich habe NSubstitute v2.0.0-rc zum Verspotten verwendet.
quelle
Kopieren Sie bei ASP.NET Core 2.x-Projekten die
appsettings.json
Datei automatisch in das Build-Verzeichnis:<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <None Include="..\MyProj\appsettings.json" CopyToOutputDirectory="PreserveNewest" /> </ItemGroup> </Project>
quelle
Wenn Sie
WebApplicationFactory
einen Testserver für Integrationstests erstellen und bereits die Möglichkeit haben, Konfigurationswerte in Ihren serverseitigen Controllern abzurufen (wahrscheinlich auch!), Können Sie diesen einfach wiederverwenden (und auf einen anderen zugreifen) injizierte Elemente, die Sie benötigen) in Ihren Integrationstests wie folgt:// 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(); } }
Beachten Sie, dass Sie
appsettings.json
in diesem Fall nicht kopieren müssen. Sie verwenden automatisch dasselbe,appsettings.json
das der (Test-) Server verwendet.quelle
appsettings.json
, unterstützt nur Entwicklung, Produktion und Staging. Wenn Sie also eine vierte Variante für Test benötigen, bin ich mir nicht sicher. Ich vermute, dass es eine Möglichkeit geben würde, eine zusätzliche Konfiguration einzufügen (da ich denke, dass alle Konfigurationen der Reihe nach durchsucht werden), die überschreiben würde, was Sie benötigen.