Delen via


De app-host beheren in .NET.NET Aspire tests

Bij het schrijven van functionele tests of integratietests met .NET.NET Aspireis het efficiënt beheren van de app-host exemplaar cruciaal. De app-host vertegenwoordigt de volledige toepassingsomgeving en kan kostbaar zijn om te maken en te afbreken. In dit artikel wordt uitgelegd hoe u de app-hostexemplaar beheert in uw .NET.NET Aspire testen.

Voor het schrijven van tests met .NET.NET Aspiregebruikt u het 📦 Aspire.Hosting.Testing NuGet-pakket met enkele helperklassen voor het beheren van het hostexemplaren van de app in uw tests.

De DistributedApplicationTestingBuilder-klasse gebruiken

In de zelfstudie over het schrijven van uw eerste testhebt u kennisgemaakt met de DistributedApplicationTestingBuilder-klasse die kan worden gebruikt om de app host-instantie te maken.

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

De DistributedApplicationTestingBuilder.CreateAsync<T>-methode neemt het projecttype van de app-host als een generieke parameter om de app-hostinstantie te creëren. Hoewel deze methode aan het begin van elke test wordt uitgevoerd, is het efficiënter om het app-hostexemplaren eenmaal te maken en deze te delen tussen tests naarmate de testsuite groeit.

Met xUnit implementeert u de IAsyncLifetime-interface op de testklasse ter ondersteuning van asynchrone initialisatie en verwijdering van het hostexemplaren van de app. De methode InitializeAsync wordt gebruikt om de app-hostinstantie te maken voordat de tests worden uitgevoerd, en de methode DisposeAsync handelt de app-host af zodra de tests zijn voltooid.

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
    }
}

Met MSTest gebruikt u de ClassInitializeAttribute en ClassCleanupAttribute op de statische methoden van de testklasse om de initialisatie en opschoning van de app-hostinstantie te bieden. De ClassInitialize methode wordt gebruikt om het app-hostexemplaren te maken voordat de tests worden uitgevoerd en de ClassCleanup methode het hostexemplaren van de app verwijdert zodra de tests zijn voltooid.

[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
    }
}

Met NUnit gebruikt u de OneTimeSetUp- en OneTimeTearDown- attributen op methoden van de testklasse om de installatie en het afbreken van de hostexemplaar van de app op te geven. De OneTimeSetUp methode wordt gebruikt om het app-hostexemplaren te maken voordat de tests worden uitgevoerd en de OneTimeTearDown methode het hostexemplaren van de app verwijdert zodra de tests zijn voltooid.

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
    }
}

Door de app-host vast te leggen in een veld wanneer de testuitvoering wordt gestart, kunt u deze in elke test openen zonder dat u deze opnieuw hoeft te maken, waardoor de tijd die nodig is om de tests uit te voeren, afneemt. Wanneer de testuitvoering is voltooid, wordt de app-host verwijderd, waarmee alle resources worden opgeschoond die tijdens de testuitvoering zijn gemaakt, zoals containers.

Argumenten doorgeven aan uw app-host

U hebt toegang tot de argumenten van uw app-host met de parameter args. Argumenten worden ook doorgegeven aan .NETconfiguratiesysteem, zodat u op deze manier veel configuratie-instellingen kunt overschrijven. In het volgende voorbeeld overschrijft u de omgeving door deze op te geven als opdrachtregeloptie:

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

Andere argumenten kunnen worden doorgegeven aan uw app-host Program en beschikbaar worden gesteld in uw app-host. In het volgende voorbeeld geeft u een argument door aan de app-host en gebruikt u dit om te bepalen of u gegevensvolumes toevoegt aan een Postgres exemplaar.

In de app-host Programgebruikt u configuratie ter ondersteuning van het in- of uitschakelen van volumes:

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

In testcode geeft u "UseVolumes=false" via de args aan de app-host door.

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>());
}

De DistributedApplicationFactory-klasse gebruiken

Hoewel de DistributedApplicationTestingBuilder-klasse nuttig is voor veel scenario's, zijn er mogelijk situaties waarin u meer controle wilt over het starten van de app-host, zoals het uitvoeren van code voordat de opbouwfunctie wordt gemaakt of nadat de app-host is gebouwd. In deze gevallen implementeert u uw eigen versie van de DistributedApplicationFactory-klasse. Dit is wat de DistributedApplicationTestingBuilder intern gebruikt.

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

De constructor vereist het type referentie van het app-hostproject als parameter. U kunt desgewenst argumenten opgeven voor de onderliggende opbouwfunctie voor hosttoepassingen. Deze argumenten bepalen hoe de app-host wordt gestart en waarden opgeven voor de argsvariabele die door het Program.cs-bestand wordt gebruikt om het hostexemplaren van de app te starten.

Levenscyclusmethoden

De DistributionApplicationFactory-klasse biedt verschillende levenscyclusmethoden die kunnen worden overschreven om aangepast gedrag te bieden tijdens de voorbereiding en het maken van de app-host. De beschikbare methoden zijn OnBuilderCreating, OnBuilderCreated, OnBuildingen OnBuilt.

We kunnen bijvoorbeeld de OnBuilderCreating methode gebruiken om configuratie in te stellen, zoals de gegevens van het abonnement en de resourcegroep voor Azure, voordat de app-host wordt gemaakt en eventuele afhankelijke Azure resources worden ingericht, wat resulteert in onze tests met behulp van de juiste Azure omgeving.

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";
    }
}

Vanwege de volgorde van prioriteit in het .NET configuratiesysteem worden de omgevingsvariabelen gebruikt voor alles in het appsettings.json- of secrets.json-bestand.

Een ander scenario dat u in de levenscyclus wilt gebruiken, is het configureren van de services die door de app-host worden gebruikt. In het volgende voorbeeld kunt u een scenario overwegen waarin u de OnBuilderCreated-API overschrijft om tolerantie toe te voegen aan de HttpClient:

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

Zie ook