Teilen über


Verwalten des App-Hosts in .NET.NET Aspire-Tests

Beim Schreiben von Funktions- oder Integrationstests mit .NET.NET Aspireist die effiziente Verwaltung des App-Hosts Instanz von entscheidender Bedeutung. Der App-Host stellt die vollständige Anwendungsumgebung dar und kann kostspielig sein, um sie zu erstellen und zu zerreißen. In diesem Artikel wird erläutert, wie Sie die App-Hostinstanz in Ihren .NET.NET Aspire Tests verwalten.

Zum Schreiben von Tests mit .NET.NET Aspireverwenden Sie das 📦 Aspire.Hosting.Testing NuGet-Paket, das einige Hilfsklassen enthält, um die App-Hostinstanz in Ihren Tests zu verwalten.

Verwenden Sie die DistributedApplicationTestingBuilder-Klasse

Im -Tutorial zum Schreiben Ihres ersten Testswurden Sie in die DistributedApplicationTestingBuilder-Klasse eingeführt, die zum Erstellen der App-Hostinstanz verwendet werden kann.

var appHost = await DistributedApplicationTestingBuilder
    .CreateAsync<Projects.AspireApp_AppHost>();

Die DistributedApplicationTestingBuilder.CreateAsync<T>-Methode verwendet den App-Hostprojekttyp als generischen Parameter, um die App-Hostinstanz zu erstellen. Während diese Methode zu Beginn jedes Tests ausgeführt wird, ist es effizienter, die App-Hostinstanz einmal zu erstellen und sie über Tests hinweg zu teilen, da die Testsuite wächst.

Mit xUnit implementieren Sie die IAsyncLifetime Schnittstelle auf der Testklasse, um asynchrone Initialisierung und Entsorgung der App-Hostinstanz zu unterstützen. Die InitializeAsync-Methode wird verwendet, um die App-Hostinstanz zu erstellen, bevor die Tests ausgeführt werden, und die DisposeAsync Methode entfernt den App-Host, sobald die Tests abgeschlossen sind.

public class WebTests : IAsyncLifetime
{
    private DistributedApplication _app;

    public async Task InitializeAsync()
    {
        var appHost = await DistributedApplicationTestingBuilder
            .CreateAsync<Projects.AspireApp_AppHost>();

        _app = await appHost.BuildAsync();
    }

    public async Task DisposeAsync() => await _app.DisposeAsync();

    [Fact]
    public async Task GetWebResourceRootReturnsOkStatusCode()
    {
        // test code here
    }
}

Mit MSTest verwenden Sie die ClassInitializeAttribute und ClassCleanupAttribute für statische Methoden der Testklasse, um die Initialisierung und Bereinigung der App-Hostinstanz bereitzustellen. Die ClassInitialize-Methode wird verwendet, um die App-Hostinstanz zu erstellen, bevor die Tests ausgeführt werden, und die ClassCleanup Methode entfernt die App-Hostinstanz, sobald die Tests abgeschlossen sind.

[TestClass]
public class WebTests
{
    private static DistributedApplication _app;

    [ClassInitialize]
    public static async Task ClassInitialize(TestContext context)
    {
       var appHost = await DistributedApplicationTestingBuilder
            .CreateAsync<Projects.AspireApp_AppHost>();

        _app = await appHost.BuildAsync();
    }

    [ClassCleanup]
    public static async Task ClassCleanup() => await _app.DisposeAsync();

    [TestMethod]
    public async Task GetWebResourceRootReturnsOkStatusCode()
    {
        // test code here
    }
}

Mit NUnit verwenden Sie die OneTimeSetUp- und OneTimeTearDown- Attribute für Methoden der Testklasse, um die Einrichtung und den Abriss der App-Hostinstanz bereitzustellen. Die OneTimeSetUp-Methode wird verwendet, um die App-Hostinstanz zu erstellen, bevor die Tests ausgeführt werden, und die OneTimeTearDown Methode entfernt die App-Hostinstanz, sobald die Tests abgeschlossen sind.

public class WebTests
{
    private DistributedApplication _app;

    [OneTimeSetUp]
    public async Task OneTimeSetup()
    {
       var appHost = await DistributedApplicationTestingBuilder
            .CreateAsync<Projects.AspireApp_AppHost>();

        _app = await appHost.BuildAsync();
    }

    [OneTimeTearDown]
    public async Task OneTimeTearDown() => await _app.DisposeAsync();

    [Test]
    public async Task GetWebResourceRootReturnsOkStatusCode()
    {
        // test code here
    }
}

Indem Sie den App-Host in einem Feld erfassen, wenn die Testausführung gestartet wird, können Sie in jedem Test darauf zugreifen, ohne dass sie neu erstellt werden müssen, wodurch die Zeit verringert wird, die zum Ausführen der Tests benötigt wird. Wenn die Testausführung abgeschlossen ist, wird der App-Host verworfen, wodurch alle Ressourcen bereinigt werden, die während der Testausführung erstellt wurden, z. B. Container.

Übergeben von Argumenten an Ihren App-Host

Sie können auf die Argumente von Ihrem App-Host mit dem parameter args zugreifen. Argumente werden auch an .NETkonfigurationssystemübergeben, sodass Sie auf diese Weise viele Konfigurationseinstellungen außer Kraft setzen können. Im folgenden Beispiel überschreiben Sie die -Umgebung, indem Sie sie als Option in der Befehlszeile angeben.

var builder = await DistributedApplicationTestingBuilder
    .CreateAsync<Projects.MyAppHost>(
    [
        "--environment=Testing"
    ]);

Andere Argumente können an Ihren App-Host Program übergeben und in Ihrem App-Host verfügbar gemacht werden. Im nächsten Beispiel übergeben Sie ein Argument an den App-Host und verwenden es, um zu steuern, ob Sie einer Postgres Instanz Datenvolumes hinzufügen.

Im App-Host Programverwenden Sie die Konfiguration, um das Aktivieren oder Deaktivieren von Volumes zu unterstützen.

var postgres = builder.AddPostgres("postgres1");
if (builder.Configuration.GetValue("UseVolumes", true))
{
    postgres.WithDataVolume();
}

Im Testcode übergeben Sie "UseVolumes=false" im args an den App-Host:

public async Task DisableVolumesFromTest()
{
    // Disable volumes in the test builder via arguments:
    using var builder = await DistributedApplicationTestingBuilder
        .CreateAsync<Projects.TestingAppHost1_AppHost>(
        [
            "UseVolumes=false"
        ]);

    // The container will have no volume annotation since we disabled volumes by passing UseVolumes=false
    var postgres = builder.Resources.Single(r => r.Name == "postgres1");

    Assert.Empty(postgres.Annotations.OfType<ContainerMountAnnotation>());
}

Verwenden Sie die DistributedApplicationFactory-Klasse

Obwohl die DistributedApplicationTestingBuilder Klasse für viele Szenarien nützlich ist, kann es Situationen geben, in denen Sie mehr Kontrolle über das Starten des App-Hosts wünschen, z. B. das Ausführen von Code, bevor der Generator erstellt wird oder nachdem der App-Host erstellt wurde. In diesen Fällen implementieren Sie Ihre eigene Version der DistributedApplicationFactory Klasse. Das ist es, was die DistributedApplicationTestingBuilder intern verwendet.

public class TestingAspireAppHost()
    : DistributedApplicationFactory(typeof(Projects.AspireApp_AppHost))
{
    // override methods here
}

Der Konstruktor erfordert den Typ der App-Host-Projektreferenz als Parameter. Optional können Sie dem zugrunde liegenden Hostanwendungs-Generator Argumente bereitstellen. Diese Argumente steuern, wie der App-Host gestartet wird, und stellen Werte für die Args-Variable bereit, die von der Datei Program.cs zum Starten der App-Hostinstanz verwendet wird.

Lifecycle-Methoden

Die DistributionApplicationFactory Klasse bietet mehrere Lebenszyklusmethoden, die überschrieben werden können, um benutzerdefiniertes Verhalten während der Vorbereitung und Erstellung des App-Hosts bereitzustellen. Die verfügbaren Methoden sind OnBuilderCreating, OnBuilderCreated, OnBuildingund OnBuilt.

Beispielsweise können wir die OnBuilderCreating Methode verwenden, um die Konfiguration festzulegen, z. B. die Informationen zur Abonnement- und Ressourcengruppe für Azure, bevor der App-Host erstellt wird und alle abhängigen Azure Ressourcen bereitgestellt werden, was dazu führt, dass unsere Tests die richtige Azure Umgebung verwenden.

public class TestingAspireAppHost() : DistributedApplicationFactory(typeof(Projects.AspireApp_AppHost))
{
    protected override void OnBuilderCreating(DistributedApplicationOptions applicationOptions, HostApplicationBuilderSettings hostOptions)
    {
        hostOptions.Configuration ??= new();
        hostOptions.Configuration["environment"] = "Development";
        hostOptions.Configuration["AZURE_SUBSCRIPTION_ID"] = "00000000-0000-0000-0000-000000000000";
        hostOptions.Configuration["AZURE_RESOURCE_GROUP"] = "my-resource-group";
    }
}

Aufgrund der Rangfolge im .NET-Konfigurationssystem werden die Umgebungsvariablen über alles in der datei appsettings.json oder secrets.json verwendet.

Ein weiteres Szenario, das Sie im Lebenszyklus verwenden möchten, besteht darin, die vom App-Host verwendeten Dienste zu konfigurieren. Betrachten Sie im folgenden Beispiel ein Szenario, in dem Sie die OnBuilderCreated-API außer Kraft setzen, um dem HttpClientResilienz hinzuzufügen:

protected override void OnBuilderCreated(
    DistributedApplicationBuilder applicationBuilder)
{
    applicationBuilder.Services.ConfigureHttpClientDefaults(clientBuilder =>
    {
        clientBuilder.AddStandardResilienceHandler();
    });
}

Siehe auch