Übung: Komponententests für eine Azure-Funktion
Komponententests sind ein grundlegender Bestandteil einer Agile-Methodik. Visual Studio stellt die Projektvorlage „Test“ bereit. Verwenden Sie diese Vorlage, um die Komponententests für Ihre Anwendungen zu erstellen. Sie können die gleiche Technik auch auf Azure Functions-Tests anwenden.
Im Szenario der Onlinewebsite für Luxusuhren verfolgt Ihr Entwicklungsteam die Strategie, in Komponententests eine Code Coverage von mindestens 80 % zu erreichen. Sie möchten die gleiche Richtlinie für Azure Functions implementieren.
In dieser Lerneinheit erfahren Sie, wie Sie das xUnit
-Testframework mit Visual Studio verwenden, um Azure Functions zu testen.
Erstellen eines Komponententestprojekts
Der erste Schritt besteht darin, ein Projekt zu erstellen, das Ihre Komponententests enthält, und es der Projektmappe hinzuzufügen, die Ihre Azure-Funktions-App enthält. Verwenden Sie die folgenden Schritte, um ein Komponententestprojekt zum Testen der WatchInfo-Funktion zu erstellen.
Klicken Sie in Visual Studio im Fenster Projektmappen-Explorer mit der rechten Maustaste auf die Projektmappe WatchPortalFunction, dann auf Hinzufügen und schließlich auf Neues Projekt.
Scrollen Sie im Fenster Neues Projekt hinzufügen nach unten, wählen Sie die Vorlage xUnit-Testprojekt C#+ und anschließend Weiter aus.
Das Fenster Neues Projekt konfigurieren wird angezeigt. Geben Sie im Feld ProjektnameWatchFunctionsTests ein. Klicken Sie neben dem Feld Speicherort auf das Suchsymbol, und wählen Sie den Ordner WatchPortalFunction aus.
Wählen Sie Weiter aus. Das Fenster Weitere Informationen wird angezeigt.
Übernehmen Sie unter Zielframework den Standardwert .NET Core 6.0 (Langfristige Unterstützung).
Klicken Sie auf Erstellen.
Wenn das Projekt hinzugefügt wurde, klicken Sie mit der rechten Maustaste auf das Projekt WatchFunctionTests im Fenster Projektmappen-Explorer und wählen dann NuGet-Pakete verwalten verwalten.
Klicken Sie im Fenster NuGet: WatchFunctionTests auf die Registerkarte Durchsuchen. Geben Sie Microsoft.AspNetCore.Mvc im Feld Suche ein. Klicken Sie auf das Paket Microsoft.AspNetCore.Mvc und dann auf Installieren.
Hinweis
Das Testprojekt erstellt eine simulierte HTTP-Umgebung. Die dafür erforderlichen Klassen befinden sich im Microsoft.AspNetCore.Mvc-Paket.
Warten Sie, während das Paket installiert wird. Wenn das Meldungsfeld Vorschau der Änderungen angezeigt wird, klicken Sie auf OK. Klicken im Meldungsfeld Zustimmung zur Lizenz auf Ich stimme zu.
Nachdem das Paket hinzugefügt wurde, klicken Sie im Fenster Projektmappen-Explorer im Projekt WatchFunctionsTests mit der rechten Maustaste auf die Datei UnitTest1.cs und wählen dann Umbenennen aus. Ändern Sie den Namen der Datei in WatchFunctionUnitTests.cs. Klicken Sie im angezeigten Meldungsfeld auf Ja, um alle Verweise von UnitTest1 in WatchFunctionUnitTests umzubenennen.
Klicken Sie im Fenster Projektmappen-Explorer im Projekt WatchFunctionsTest mit der rechten Maustaste auf Abhängigkeiten, und wählen Sie dann Projektverweis hinzufügen aus.
Wählen Sie im Fenster Verweis-Manager das Projekt WatchPortalFunction aus, und klicken Sie dann auf OK.
Hinzufügen von Komponententests für die WatchInfo-Funktion
Sie können dem Testprojekt nun die Komponententests hinzufügen. Im Luxusuhrenszenario möchten Sie sicherstellen, dass die WatchInfo-Funktion immer eine Antwort OK zurückgibt, wenn ein Modell in der Abfragezeichenfolge einer Anforderung angegeben ist, und eine Antwort Bad, wenn die Abfragezeichenfolge leer ist oder den Parameter model
nicht enthält.
Fügen Sie WatchFunctionsTests zwei Fact-Tests hinzu, um dieses Verhalten zu überprüfen.
Doppelklicken Sie im Fenster Projektmappen-Explorer auf die Datei WatchFunctionUnitTests.cs, um „WatchPortalFunction“ im Codefenster anzuzeigen.
Fügen Sie der Liste am Anfang der Datei die folgenden
using
-Anweisungen hinzu.using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Logging.Abstractions;
Ändern Sie den Namen der Test1-Methode in TestWatchFunctionSuccess.
Fügen Sie im Hauptteil der TestWatchFunctionSuccess-Methode den folgenden Code hinzu. Diese Anweisung erstellt einen simulierten HTTP-Kontext und eine simulierte HTTP-Anforderung. Die Anforderung umfasst eine Abfragezeichenfolge, die den
model
-Parameter enthält, der aufabc
festgelegt ist.var queryStringValue = "abc"; var request = new DefaultHttpRequest(new DefaultHttpContext()) { Query = new QueryCollection ( new System.Collections.Generic.Dictionary<string, StringValues>() { { "model", queryStringValue } } ) };
Fügen Sie der Methode die folgende Anweisung hinzu. Diese Anweisung erstellt eine simulierte Protokollierung.
var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
Fügen Sie der Methode den folgenden Code hinzu. Diese Anweisungen rufen die WatchInfo-Funktion auf und übergeben die simulierte Anforderung und die Protokollierung als Parameter.
var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait();
Fügen Sie der Methode den folgenden Code hinzu. Dieser Code überprüft, ob die Antwort der Funktion richtig ist. In diesem Fall sollte die Funktion eine Antwort OK zurückgeben, die die erwarteten Daten im Textteil enthält.
// Check that the response is an "OK" response Assert.IsAssignableFrom<OkObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (OkObjectResult)response.Result; dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 }; string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}"; Assert.Equal(watchInfo, result.Value);
Die vollständige Methode sollte wie folgt aussehen:
[Fact] public void TestWatchFunctionSuccess() { var queryStringValue = "abc"; var request = new DefaultHttpRequest(new DefaultHttpContext()) { Query = new QueryCollection ( new System.Collections.Generic.Dictionary<string, StringValues>() { { "model", queryStringValue } } ) }; var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger"); var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait(); // Check that the response is an "OK" response Assert.IsAssignableFrom<OkObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (OkObjectResult)response.Result; dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 }; string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}"; Assert.Equal(watchInfo, result.Value); }
Fügen Sie zwei weitere Methoden namens TestWatchFunctionFailureNoQueryString und TestWatchFunctionFailureNoModel hinzu. TestWatchFunctionFailureNoQueryString stellt sicher, dass die WatchInfo-Funktion ordnungsgemäß fehlschlägt, wenn sie keine Abfragezeichenfolge erhält. TestWatchFunctionFailureNoModel prüft auf den gleichen Fehler, wenn der Funktion eine Abfragezeichenfolge übergeben wird, die keinen Modellparameter enthält.
[Fact] public void TestWatchFunctionFailureNoQueryString() { var request = new DefaultHttpRequest(new DefaultHttpContext()); var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger"); var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait(); // Check that the response is an "Bad" response Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (BadRequestObjectResult)response.Result; Assert.Equal("Please provide a watch model in the query string", result.Value); } [Fact] public void TestWatchFunctionFailureNoModel() { var queryStringValue = "abc"; var request = new DefaultHttpRequest(new DefaultHttpContext()) { Query = new QueryCollection ( new System.Collections.Generic.Dictionary<string, StringValues>() { { "not-model", queryStringValue } } ) }; var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger"); var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait(); // Check that the response is an "Bad" response Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (BadRequestObjectResult)response.Result; Assert.Equal("Please provide a watch model in the query string", result.Value); }
Ausführen der Tests
Wählen Sie auf der oberen Menüleiste unter Test die Option Alle Tests ausführen aus.
Im Fenster Test-Explorer sollten alle drei Tests erfolgreich abgeschlossen werden.
Doppelklicken Sie im Fenster Projektmappen-Explorer unter dem Projekt WatchPortalFunction auf WatchInfo.cs, um die Datei im Code-Editor anzuzeigen.
Suchen Sie nach dem folgenden Code:
// Retrieve the model id from the query string string model = req.Query["model"];
Ändern Sie die Anweisung, die die
model
-Variable festgelegt, wie folgt. Diese Änderung simuliert, dass der Entwickler einen Fehler im Code macht.string model = req.Query["modelll"];
Wählen Sie auf der oberen Menüleiste unter Test die Option Alle Tests ausführen aus. Dieses Mal sollte TestWatchFunctionSuccess fehlschlagen. Dieser Fehler tritt auf, da die WatchInfo-Funktion den
modelll
-Parameter in der Abfragezeichenfolge nicht gefunden hat und die Funktion daher eine Bad-Antwort zurückgegeben hat.
In dieser Lerneinheit haben Sie gesehen, wie Sie ein Komponententestprojekt erstellen und Komponententests für eine Azure-Funktion implementieren.