In Lektion 3.8.1 stand ein Absatz über Aspire-Tests im Überblick, und darin der Satz: Solche Tests sind langsam, weil sie alles starten, und sie prüfen viel auf einmal; nehmen Sie sie für wenige Wege von Ende zu Ende. Diese Lektion baut genau einen solchen Weg: Eine Besucherin bucht einen Termin, die Kladde speichert die Buchung, die Outbox verschickt die Bestätigung. Dazwischen liegen die Web-App, SQL Server, die Migrationen, der Hintergrunddienst der Outbox und die Konfiguration, die der AppHost allen mitgibt. Kein anderer Test der Kladde prüft das Zusammenspiel all dieser Teile mit der Verdrahtung, mit der sie auch auf Ihrem Rechner laufen.

Der ganze AppHost im Test

Das Paket Aspire.Hosting.Testing startet einen AppHost in einem Test. Der Test bekommt dasselbe Modell, das aspire run startet, mit drei Unterschieden: Das Dashboard ist aus, die Ports sind zufällig gewählt, damit mehrere Läufe nebeneinander gehen, und der Test kann das Modell vor dem Start ändern.

C#
IDistributedApplicationTestingBuilder builder =
    await DistributedApplicationTestingBuilder.CreateAsync<Projects.Kladde_AppHost>(args, cancellationToken);
// ... change the model ...
DistributedApplication app = await builder.BuildAsync(cancellationToken);
await app.StartAsync(cancellationToken);
await app.ResourceNotifications.WaitForResourceHealthyAsync("web", cancellationToken);
  • CreateAsync<Projects.Kladde_AppHost>(args, …) führt AppHost.cs aus, bis zu builder.Build(), und hält das Modell an, bevor etwas startet. Projects.Kladde_AppHost gibt es, sobald das Testprojekt den AppHost referenziert. args kommen in die Konfiguration des AppHost, wie bei aspire run -- ….
  • BuildAsync und StartAsync bauen und starten das Modell. StartAsync kehrt zurück, wenn alles gestartet ist, nicht, wenn alles bereit ist.
  • ResourceNotifications.WaitForResourceHealthyAsync("web", …) wartet, bis der Health Check aus Lektion 3.14.1 gelingt. Weil web erst nach den Migrationen startet und /health/ready die Datenbank prüft, wartet der Test damit auf alles, was eine Buchung braucht.
  • app.CreateHttpClient("web", "https") gibt einen HttpClient, dessen Basisadresse der Endpunkt https von web ist, mit dem zufälligen Port dieses Laufs.
  • app.ResourceCommands.ExecuteCommandAsync("web", "testdaten", …) führt einen Befehl aus wie das Dashboard, auch den aus Lektion 3.14.1. Sein Ergebnis steht in Success, Message und, mit ResultMode = HttpCommandResultMode.Text, in Data.Value.

Ein Aspire-Test startet Prozesse und Container, keine Klassen im Testprozess. Sie können also keinen Dienst im Container der Web-App ersetzen, wie es WebApplicationFactory erlaubt. Was ein Test ändern will, ändert er über das Modell: Argumente, Umgebungsvariablen, Ressourcen.