Blog

Lassen Sie uns mit .NET 6 MVC Playwright spielen

Kristof Riebbels

Kristof Riebbels

Aktualisiert Oktober 15, 2025
21 Minuten

Beginnen wir diese Geschichte mit unserem Protagonisten, einem Berater in der Rolle eines Backend-Entwicklers mit Schwerpunkt auf .NET 6 und Azure. Lassen Sie uns ihn Mike nennen. Mike liebt es, Qualität zu liefern. Er arbeitet mit automatisierten Unit-Tests und Integrationstests und sorgt dafür, dass diese in der CI-Pipeline des Projekts ausgeführt werden. Er verwendet XUnit und NSubstitute, WireMock.Net und FluentAssertions.

Mike steht vor einer neuen Herausforderung. Da Kollegen das Projekt verlassen haben, wurde er gebeten, ein Frontend zu liefern, das in Dotnet 6 MVC erstellt wurde. Unser Berater hat einige Nachforschungen zur Webentwicklung angestellt. Mike hat seine Arbeit gerne getestet, als er das Backend entwickelt hat.

Der Übergang von Mike zu einem Full-Stack-Entwickler bedeutet eine erhebliche Verschiebung der Perspektive. Mike war nur auf serverseitige Logik und Datenverwaltung konzentriert. Jetzt muss er das Wissen über die Webentwicklung erforschen und begreifen und vor allem die üblichen Fallstricke entdecken.

Ziel dieses Artikels ist es, die Geschichte von Mikes Übergang von einem Backend-Entwickler zu einem Full-Stack-Entwickler zu erzählen. Die Welt schien für ihn einfacher zu sein, als das Testen noch eine einfache Sache war, wenn man SOLID in einer Backend-Umgebung programmiert. Das Testen der Benutzeroberfläche bringt seine Schwierigkeiten mit sich. Mike wird ein Playwright-Projekt erstellen und herausfinden, wie Playwright mit diesen Schwierigkeiten umgeht.

Besuchen Sie das dotnet6mvc-Playwright-Repository (siehe Referenzen), um mit Playwright zu spielen.

Die Sichtweise der Backend- und Frontend-Entwickler

Mike entdeckt und spürt die zusätzlichen Probleme, die die Frontend-Entwicklung mit sich bringt. Er ist kein Frontend-Entwickler, aber er ist bereit, die Welt der Frontend-Entwicklung zu lernen. Lassen Sie uns untersuchen, was er bisher gelernt hat.

In Mikes Welt erstellen Backend-Entwickler Anwendungen und stellen mit Hilfe von Unit-Tests sicher, dass diese Anwendungen zuverlässig und belastbar sind. Traditionell waren für Integrationstests eine Menge Einstellungen und eine Live-Umgebung erforderlich. Mike führt jedoch Integrationstests in seiner CI-Pipeline durch, indem er andere Dienste einbindet und mit ihnen arbeitet! Das Mocking von HTTP-Aufrufen ist heutzutage ein Kinderspiel. Mike mockt Code, der mit Nicht-HTTP-Diensten integriert wird, und er verwendet dafür Mocking-Frameworks. Mike verwendet In-Memory-Datenbanken, so dass er nicht auf eine echte Datenbank angewiesen ist. Wenn eine Live-Umgebung noch QA-Tests durch potenzielle Endbenutzer erfordert, kommt Infrastructure as Code (IaC) zur Hilfe.

Full-Stack-Entwickler müssen sich auf die Handhabung des clientseitigen Codes konzentrieren. Einige arbeiten mit VanillaJS, während andere mit einem Framework arbeiten, das auf dem neuesten Stand gehalten werden muss. Sie müssen untersuchen, welche Auswirkungen dies auf den Endbenutzer haben kann. Es gibt viele verschiedene Frameworks zur Auswahl und jedes hat seine Vor- und Nachteile.

Wenn Mike über Frontend-Entwicklung nachdenkt, fällt ihm auf, dass die Entwicklung überwiegend in JavaScript erfolgt, einer Sprache, die robuste Unterstützung für asynchrone Programmierung bietet. Die Entwickler müssen sich Gedanken über die Ausführungsreihenfolge des Codes und die Größe der Nutzdaten machen, die sie an den Server senden und abrufen, und die Anzahl der Anfragen begrenzen. Die Benutzeroberfläche muss so schnell wie möglich geladen werden, daher ist es wichtig, Skripte zu verkleinern und aufzuteilen.

Einige Frameworks generieren HTML für Sie. Mike mag Typsicherheit und einige Tools, die ihm dabei helfen. Er ist nur daran interessiert, sicherzustellen, dass die REST-API durch ein Bearer-Token geschützt ist und herauszufinden, welche Art der Authentifizierung er für die Abfrage von Datenbanken verwenden würde. Jetzt muss Mike darüber nachdenken, wie er Benutzer mithilfe von Authentifizierungs- und Autorisierungsabläufen über das OpenID-Protokoll identifizieren kann.

Da das Frontend das erste ist, womit Benutzer und Hacker konfrontiert werden, müssen Frontend-Entwickler sicherstellen, dass ihre Skripttechniken auf dem neuesten Stand sind und die verwendeten Bibliotheken nicht angreifbar sind.

Client-seitiger Code muss in allen möglichen Browsern laufen. Ist es für Mike zu viel verlangt, ein Cloud-Tool zu verwenden, das mehrere verschiedene Browser anbietet, um die Anwendung manuell auf allen möglichen Geräten zu testen?

Ein kleines Stück Geschichte

Mike möchte verstehen, was in der Vergangenheit geschehen ist. Er möchte wissen, wie die Herausforderungen in der Vergangenheit angegangen wurden und wo wir heute stehen. Er glaubt, dass das Verständnis der Vergangenheit ihm helfen wird, die Gegenwart und die Zukunft zu verstehen.

In den 1980er und 1990er Jahren, als Personal Computer immer beliebter wurden, begannen Softwareanwendungen komplexere Benutzeroberflächen zu haben. Dies führte zur Entwicklung von automatisierten UI-Testtools. Diese Tools ermöglichten es den Testern, Benutzerinteraktionen aufzuzeichnen und wiederzugeben, was das Testen komplexer Oberflächen erleichterte.

In den 2000er Jahren, als Webanwendungen aufkamen, entwickelte sich das Testen der Benutzeroberfläche weiter. Webanwendungen haben komplexere Schnittstellen und sind dynamischer als herkömmliche Desktop-Anwendungen. Dies führte zur Entwicklung von fortschrittlicheren UI-Testing-Tools wie Selenium, die mit Web-Elementen interagieren können.

In den letzten Jahren, mit dem Aufkommen mobiler Anwendungen, mussten sich UI-Tests noch einmal anpassen. Mobile Anwendungen haben andere Schnittstellen und Interaktionsmuster als Web- oder Desktop-Anwendungen. Dies hat zur Entwicklung neuer UI-Testing-Tools geführt, die speziell für mobile Anwendungen konzipiert sind.

Mit dem Aufkommen der Arbeit mit Paketen ist ein Frontend-Entwickler in der Lage, Komponenten wiederzuverwenden. Das bedeutet, dass Unit-Tests zum Testen einzelner Komponenten verwendet werden können: einzelne Schaltflächen, Formulare oder andere UI-Elemente.

Wenn Sie Tests für diese Komponenten hinzufügen, können Sie mit Integrationstests die Interaktion zwischen den Komponenten testen.

Häufige Probleme bei UI-Tests

Mike besuchte mit einigen Kollegen eine Konferenz und nahm an einem Vortrag über UI-Tests teil. Nach dieser Sitzung hörte er sich genau an, was andere über die Schwierigkeiten beim UI-Testen zu sagen hatten. Nachfolgend finden Sie eine Liste dessen, was er gehört hat.

  • Dynamische Inhalte, komplexe Schnittstellen, browserübergreifende Kompatibilität, Ressourcen, Timing, Interaktion und mobile Kompatibilität sind einige der häufigsten Herausforderungen beim Testen von Benutzeroberflächen.
  • Moderne Webanwendungen haben oft dynamische Inhalte, die sich als Reaktion auf Benutzerinteraktionen ändern. Das kann es schwierig machen, Tests zu schreiben, die zuverlässig und wiederholbar sind. Dynamische Inhalte beziehen sich auf Webseiten, die je nach Benutzer, Tageszeit oder Gerät des Benutzers unterschiedliche Texte, Bilder oder Layouts anzeigen. Inkonsistente Bezeichner wie IDs, Namen und Klassen sind in verschiedenen Versionen der Webanwendung möglicherweise nicht immer eindeutig oder konsistent, was es für das Automatisierungsskript schwierig macht, Elemente genau zu finden.
  • Um Tests durchführen zu können, muss ein System vorhanden sein, mit dem getestet werden kann. Dieses System muss auf dem neuesten Stand sein und in der richtigen Umgebung laufen. Das kann an sich schon eine Herausforderung sein. Hier kann ihm das Backend-For-Frontend (BFF) Muster helfen. Das BFF-Muster ist ein Software-Designmuster, das es Entwicklern ermöglicht, ein einziges Backend für eine Frontend-Anwendung zu erstellen. Dieses Muster ist nützlich, wenn Sie eine oder mehrere Frontend-Anwendungen haben, die auf dieselben Daten oder Funktionen zugreifen müssen. Es kann auch verwendet werden, um eine einzige API für mehrere Versionen der gleichen Frontend-Anwendung zu erstellen. Auf diese Weise lässt sich das Backend leicht ausmocken.
  • Nicht alle Interaktionen können getestet werden. Wenn die Anwendung mit APIs von Drittanbietern kommuniziert, die nicht über entsprechende Daten verfügen oder keine Testumgebung bereitstellen, ist es schwierig, die Anwendung zu testen.
  • Einige Anwendungen haben komplexe Schnittstellen mit vielen Elementen. Das kann es schwierig machen, Tests zu schreiben, die alle möglichen Benutzerinteraktionen abdecken. Einige Webanwendungen beinhalten komplexe Benutzerinteraktionen wie Drag-and-Drop, Hover-Menüs oder Tastenkombinationen, die sich nur schwer automatisieren lassen.
  • Verschiedene Browser können Webseiten auf leicht unterschiedliche Weise darstellen. Das kann es schwierig machen, Tests zu schreiben, die auf allen Browsern korrekt funktionieren.
  • Mobile Geräte haben andere Bildschirmgrößen und Interaktionsmuster als Desktop-Geräte. Das kann es schwierig machen, Tests zu schreiben, die sowohl auf mobilen als auch auf Desktop-Geräten korrekt funktionieren.
  • In der Produktentwicklung erfordern die kontinuierliche Weiterentwicklung und Anpassung von Produkten regelmäßige Aktualisierungen und die Pflege von UI-Tests, aber die Fragilität und der hohe Wartungsaufwand können die Motivation zur Entwicklung dieser Tests verringern. In der Projektentwicklung können der vordefinierte Umfang und die begrenzten Änderungen zu minimaler Redundanz bei den UI-Tests führen, aber strenge Verträge oder enge Fristen können die Motivation, sie zu schreiben, aufgrund von Schwierigkeiten bei der nachträglichen Änderung von Tests beeinträchtigen...

Dramatiker ist das neue Kind im Block

Als Mike sein Verständnis der Frontend-Entwicklung vertieft, erkennt er den Nutzen von Tools wie Selenium und Playwright für Komponententests und End-to-End-Simulationen der Benutzerinteraktion. Er entdeckt, dass Selenium ein gut etabliertes Framework ist. Selenium genießt den Ruf, zuverlässig und vielseitig zu sein. Selenium bietet browserübergreifende Tests und unterstützt eine Vielzahl von Programmiersprachen. Es erleichtert Frontend-UI-Tests auf echten Servern und Cloud-basierte Tests mit echten Geräten.

Trotz des guten Rufs von Selenium tendiert Mike zu Playwright. Playwright wurde von Microsoft entwickelt und bietet einige Vorteile, die ihm gefallen. Die Unterstützung von Playwright für die Headless-Browser-Architektur ermöglicht einen schnelleren Feedback-Zyklus. Für einen Backend-Entwickler, der die Frontend-Entwicklung erlernt, ist das eine nützliche Funktion (Lebensqualität)! Der automatische Wartemechanismus von Playwright reduziert die Instabilität von Tests. Er hat über die isolierten Browser-Kontexte gelesen. Mit diesen isolierten Kontexten können Sie Tests unabhängig voneinander durchführen, ohne gemeinsamen Status und gleichzeitige Benutzeranmeldungen. Auch das Debugging wird einfacher. Mike muss sich nicht um die Resteffekte von früheren Tests kümmern. Playwright kann verschiedene Geräte und geografische Standorte emulieren. Diese Funktionen ermöglichen es ihm, alle Arten von Benutzerszenarien nachzustellen.

Dramatiker eingeben

Playwright ist eine von Microsoft entwickelte Open-Source-Node-Bibliothek, die es Entwicklern ermöglicht, Webbrowser über die Protokolle Chromium, Firefox und WebKit zu automatisieren. Sie bietet Funktionen für die Interaktion mit Webseiten, die Auswertung von Skripten, die Erstellung von Screenshots und die Erstellung von PDFs. Es wird für End-to-End-Tests von Webanwendungen verwendet, um deren korrekte Funktionalität in verschiedenen Webbrowsern sicherzustellen.

Playwright hat sich aus dem Puppeteer-Projekt entwickelt. Dieses war auf die Automatisierung von Chrome beschränkt. Microsofts Bemühungen mit Playwright zielen darauf ab, das Multi-Browser-Szenario zu adressieren und es zu ermöglichen, dieselben Tests auf verschiedenen Browsern auszuführen, ohne dass der Code geändert werden muss. Dies ist ein großer Fortschritt, denn viele Unternehmen müssen sicherstellen, dass ihre Webanwendungen nahtlos in allen wichtigen Browsern funktionieren.

Die .NET-Community zeigte Interesse daran, die Fähigkeiten von Playwright in ihrem Ökosystem zu nutzen. Microsoft hat diese Nachfrage erkannt und Playwright für .NET eingeführt, mit dem .NET-Entwickler Tests in C# schreiben können.

Playwright für .NET ist ein Client-Paket, das die Kommunikation mit dem Playwright Node.js Server ermöglicht. Anstatt Mikes Tests in JavaScript zu schreiben, bringt es die Playwright-API zu .NET-Entwicklern. Da es sich um ein Client-Server-Modell handelt, verfügt Mike über dieselbe zugrunde liegende Browser-Automatisierungs-Engine und kann somit dieselben Funktionen nutzen.

Funktionen, die Playwright großartig machen

Mike möchte wissen, was er mit Playwright tun kann und entdeckt auf der Playwright-Website die folgenden Funktionen:

  • Playwright automatisiert die Browser Chromium, WebKit und Firefox mit einer einzigen API, die alle Rendering-Engines abdeckt.
  • Mit Playwright können Sie testen, wie sich eine Anwendung auf verschiedenen Geräten verhält, indem Sie die Größe des Ansichtsfensters des Browsers anpassen.
  • Playwright ermöglicht auch eine Netzwerkdrosselung, bei der Entwickler langsame Netzwerkverbindungen simulieren und die Auswirkungen auf die Leistung der Anwendung bewerten können. Mit den in Playwright integrierten Funktionen zur Netzwerkverwaltung können Entwickler langsame oder offline Netzwerkbedingungen emulieren, um zu messen, wie die Anwendung in verschiedenen Szenarien abschneidet.
  • Um UI-Tests zu beschleunigen, können Entwickler die parallele Testausführung nutzen. Der Auto-Wait-Mechanismus von Playwright und die Unterstützung für das Abfangen von Netzwerkanfragen machen es ideal für das Testen von Single-Page-Anwendungen (SPAs). Entwickler können sicherstellen, dass wichtige Seitenelemente verfügbar sind und die Anwendung während der Navigation und der Benutzerinteraktionen die erwarteten API-Aufrufe tätigt.
  • Playwright ermöglicht es Entwicklern, das Testen der Formularübermittlung und -validierung zu automatisieren.
  • Playwright bietet die Möglichkeit, die Authentifizierung des Browsers wiederzuverwenden, wodurch das Testen von Anwendungen erleichtert wird.
  • Mit Playwright können Sie Browser-Interaktionen automatisieren, die Sie entweder mit oder ohne Kopfzeile ausführen können.
  • Playwright verfügt über einige Funktionen zur Erstellung von Screenshots und zur Aufnahme von Videos Ihrer Browser-Sitzungen. Das hilft Ihnen bei der Fehlersuche, der Dokumentation und sogar bei der visuellen Überprüfung. Kombinieren Sie diese Strategie mit einer CI/CD-Pipeline, und Sie haben mehr Kontext, wenn ein Test fehlschlägt.

Mit Kopf gegen kopflos

Also gut, Mike geht auf die Begriffe headless und head im Zusammenhang mit Browsern und Unit-Tests sowie Playwright ein.

Wenn Mike einen Browser im Modus headed ausführt, bedeutet dies, dass er die gesamte grafische Benutzeroberfläche sieht. Mike sieht, wie die Webseiten geladen werden, und er kann herumklicken - das ganze Drum und Dran.

Im Modus headless läuft der Browser ohne eine grafische Benutzeroberfläche. Es geschieht alles im Hintergrund, so dass Mike es nicht sehen kann, aber es ist da und tut seine Arbeit. Dies ist sehr nützlich für automatisierte Aufgaben, Serverumgebungen oder Testszenarien, bei denen Sie die grafische Benutzeroberfläche nicht benötigen.

Bei Unit-Tests beziehen sich headless und headed in der Regel darauf, wie Tests in einem Browser ausgeführt werden. Wenn Mikes Tests in einem sichtbaren Browserfenster (headed) ausgeführt werden, kann er beobachten, wie der Browser durch die Testschritte navigiert. Das ist zwar langsamer, aber gut zum Debuggen.

Wenn der Browser im Hintergrund bleibt (headless), sieht Mike keine grafische Benutzeroberfläche. Auf diese Weise laufen die Tests schneller ab. Das ist ideal für CI/CD-Pipelines, bei denen Mike nur wissen möchte, ob die Tests erfolgreich waren oder nicht, ohne den visuellen Overhead.

Mikes Einführung in UI-Tests mit Playwright in .NET 6 MVC

Folgen wir Mikes Schritten, wie Sie mit Playwright in .NET 6 MVC beginnen können, indem wir die Dokumentation von Playwright verwenden.

Mike hat die Webanwendung von jemandem gesucht und wiederverwendet. Er fand eine in Dotnet 6 MVC geschriebene E-Commerce-Website. Es handelt sich um eine kleine Anwendung, bei der der Benutzer erstellt werden muss und die Berechtigung haben muss, eine Liste von Produkten anzusehen, zu erstellen und/oder zu aktualisieren. Mike stellt sicher, dass die Anwendung läuft und er auf die Webseite zugreifen kann.

Mike liest, dass Playwright für .NET am besten mit NUnit funktioniert. Playwright unterstützt zwar auch andere Test-Runner wie MSTest, aber Mike wird NUnit verwenden. Das Hauptaugenmerk der Playwright-Testrunner liegt auf der Optimierung der Testleistung durch die Wiederverwendung von Playwright- und Browser-Instanzen und die Ausführung jedes Testfalls in einem neuen BrowserContext, um Browser-Zustände zu isolieren.

Playwright unterstützt die Parallelisierung von Tests nicht. Standardmäßig führen NUnit, MSTest und XUnit alle Testdateien parallel aus. Playwright bietet Unterstützung für die Konfiguration von NUnit und MSTest, so dass jeder Test innerhalb einer Testdatei sequentiell ausgeführt wird. Um NUnit einzurichten, gibt es die Option ParallelScope.Self, so viele Prozesse zu erstellen, wie es Kerne auf dem Hostsystem gibt. Die parallele Ausführung von Tests mit ParallelScope.All oder ParallelScope.Fixtures wird nicht unterstützt.

Mike folgte der Anleitung von Playwright mit Leichtigkeit. Er kopiert einen Test, der Playwright.dev besucht und den Titel der Homepage überprüft. Als er den Test ausführte, war er froh, dass er grün wurde.

Er begann jedoch, das Werkzeug in Frage zu stellen. Er sah nicht, dass etwas passierte. Er wusste, dass das Tool die Erstellung von Screenshots unterstützt. Er fügte eine Codezeile hinzu, die einen Bildschirmausdruck von der Seite anfertigt. Der Screenshot wird im Ordner bin/Debug/net6.0 gespeichert.


await Page.ScreenshotAsync(new PageScreenshotOptions { Path = "image.png" });

Er führte den Test erneut aus und sah den Screenshot im Ordner bin/Debug/net6.0 erscheinen

Mike durchsuchte den Debug-Ordner und bemerkte Dateien und Ordner, die mit Playwright zusammenhängen:

  • einen Ordner namens .playwright: Dieser Ordner enthält zwei weitere Ordner, die NodeJS und den Playwright-Code enthalten
  • eine Datei mit dem Namen playwright.ps1: Eine PowerShell-Datei, die die Methode Program.Main in der Datei Microsoft.Playwright.dll ausführen wird.
  • Microsoft Playwright DLLs: Der Code, der die Kommunikation mit dem Playwright NodeJs Server sicherstellt.

Da Mike den Ordner .playwright entdeckt hat, wurde er neugierig darauf, wie sich der Code im Test verhält. Um diesen Prozess zu verstehen, muss er die Architektur verstehen. Mike fand heraus, dass Playwright alle Anfragen über eine einzige Web-Socket-Verbindung übermittelt. Diese Verbindung bleibt bestehen, bis die Testausführung abgeschlossen ist. Dadurch werden Fehlerquellen reduziert und die Befehle können schnell über eine einzige Verbindung gesendet werden. Playwright verwendet außerdem eine einzige Browser-Instanz für alle Tests. Dadurch wird der Aufwand für das Erstellen und Zerstören von Browser-Instanzen reduziert.

Mike ist nun bereit, seine Tests zu schreiben. Er möchte die Anmeldeseite der Anwendung testen. Um dieses Ziel zu erreichen, muss er die E-Commerce-Anwendung starten. Er hat die Microsoft-Dokumentation über die Erstellung von Integrationstests gelesen und die Anwendung mit WebApplicationFactory gestartet.

Die WebApplicationFactory dient als In-Memory-Host für Mikes Webanwendung. Das Besondere an WebApplicationFactory ist die Verwendung eines DeferredHostBuilder. Die Webanwendung wird gestartet, unmittelbar bevor HttpClient erstellt wird. Die Sequenzen der Methodenaufrufe in Program.cs werden von WebApplicationFactory aufgezeichnet, ohne dass sie ausgeführt werden. Dies gibt Mike die Flexibilität, registrierte Dienste außer Kraft zu setzen, was nützlich ist, um sicherzustellen, dass die Anwendung und die Tests nicht auf Dritte (z.B. eine Datenbank) zugreifen.

Mike erstellt eine HttpClient mit der WebApplicationFactory.CreateClient, um auf die E-Commerce-Webseite zuzugreifen, und er ruft die Homepage auf! Als er begann, seine ersten Playwright-Tests zu schreiben, bemerkte er die folgende Fehlermeldung.


Message:  Microsoft.Playwright.PlaywrightException : 
net::ERR_CONNECTION_REFUSED at http://localhost/ 
=========================== logs =========================== 
navigating to "http://localhost/", waiting until "load" 
============================================================

Bei der Suche im Internet fand Mike heraus, dass WebApplicationFactory im Moment nicht gut geeignet ist. Diese Klasse ist eng mit dem HTTP-Server namens TestServer gekoppelt. Der TestServer kann unsere Anwendung hosten und ist über den HttpClient ansprechbar, der durch die Methode WebApplicationFactory.CreateDefaultClient erstellt wird. Externe Prozesse, wie z.B. Playwright, können nicht auf die E-Commerce-Webanwendung zugreifen.

Eine Lösung ist die Verwendung von Kestrel. Kestrel kann die Endpunkte und Seiten der Anwendung offenlegen. Playwright kann dann mit der Anwendung interagieren. Als Mike weiter recherchierte, las er einige Threads in der Issues-Liste von Dotnet auf GitHub. Microsoft wird einige Überarbeitungen vornehmen, allerdings ist dies keine Priorität für DotNet 7 und scheint im Moment für DotNet 8 in der Triage zu sein.

Mike erstellt eine Klasse, die WebApplicationFactory erweitert und PlaywrightCompatibleWebApplicationFactory heißt. Wenn Sie sich den Code unten ansehen, bemerkt Mike die Erstellung von zwei Hosts.


protected override IHost CreateHost(IHostBuilder builder) { 
    try {  
        _hostThatRunsTestServer = builder.Build(); 
        builder.ConfigureWebHost(webHostBuilder => webHostBuilder.UseKestrel()); 
        _hostThatRunsKestrelImpl = builder.Build(); 
        _hostThatRunsKestrelImpl.Start(); 
        var server = _hostThatRunsKestrelImpl.Services.GetRequiredService(); 
        var addresses = server.Features.Get(); 
        ClientOptions.BaseAddress = addresses!.Addresses.Select(x => new Uri(x)).Last(); 
        _hostThatRunsTestServer.Start(); 
        return _hostThatRunsTestServer;
    } 
    catch (Exception e) { 
        _hostThatRunsKestrelImpl?.Dispose(); 
        _hostThatRunsTestServer?.Dispose(); 
        throw; 
    } 
}

Die Anwendung möchte ein Host erstellen, das den HTTP-Server TestServer kapselt. Das bedeutet, dass Mike einen zusätzlichen HTTP-Server Kestrel erstellen muss. Mike benötigt diesen, weil WebApplicationFactory eine Eigenschaft namens Server offenlegt. Diese Eigenschaft zeigt den Typ TestServer und nicht den Typ IServer an. Der Host von TestServerwird zuerst erstellt. Wenn Mike zuerst Kestrel auf dem Builder konfiguriert und dann eine Instanz von KestrelImpl abruft, kann er keine Instanz des Typs TestServer zurückgeben.

Jetzt ist die Anwendung für die Außenwelt zugänglich und daher wollte er für Playwright einige Tests schreiben. Er begann mit einem einfachen Test, der die Anmeldeseite aufruft und den Titel der Seite prüft. Dazu verwendet er den Codegenerator, den Playwright anbietet. Wenn er .Playwright.ps1 codegen ausführt, erscheint ein Fenster namens Playwright Inspector.

In diesem Fenster ist Mike ein Code aufgefallen, der für Sie generiert wird:

Start der Codegenerierung

Start der Codegenerierung

Als Mike auf das Dropdown-Feld Ziel klickt, sieht er eine Liste von Sprachen: Er kann C#, Java, Python oder JavaScript verwenden. Mike ist mit diesen anderen Sprachen nicht vertraut, also bleibt er bei C# und wählt NUnit.

Unterstützte Sprachen

Unterstützte Sprachen

Mike fuhr mit dem Mauszeiger über die Elemente im Browser und stellte fest, dass Playwright das Element markiert hatte. Playwrights fügte eine Beschriftung unter dem markierten Element hinzu. Dieses Etikett enthält den Locator zum Abrufen des Elements. Mike kann diesen Locator kopieren und ihn in seinen Tests verwenden.

Bewegen Sie die Maus über ein Element und lassen Sie sich den Locator anzeigen

Bewegen Sie die Maus über ein Element und lassen Sie sich den Locator anzeigen

Mike klickte und drückte einige Tasten, während er seine Aktionen aufzeichnete, um seinen ersten Test durchzuführen: Er konnte sich nicht mit den falschen Anmeldedaten anmelden.


[Test] 
public async Task MyTest() { 
    await Page.GotoAsync("https://localhost:44304/Identity/Account/Login?ReturnUrl=%2F"); 
    await Page.GetByLabel("Email").ClickAsync(); 
    await Page.GetByLabel("Email").FillAsync("test@test.be"); 
    await Page.GetByLabel("Email").PressAsync("Tab"); 
    await Page.GetByLabel("Password").FillAsync("ABc.123!"); 
    await Page.GetByRole(AriaRole.Button, new() { Name = "Log in" }).ClickAsync(); 
    await Page.GetByText("Invalid login attempt.").ClickAsync(); 
}

Mit einigen Anpassungen erstellte Mike manuell zwei Tests aus den aufgezeichneten Benutzerinteraktionen unter Verwendung der Playwright Inspector.

  • Eine, um zu überprüfen, ob die Umleitung funktioniert
    
      [Test] 
      public async Task WhenProvidingBaseUrl_ShouldRedirectToLoginPage() { 
          await Page.GotoAsync(_webApplicationFactory.ServerAddress); //Should be redirected. 
          await Expect(Page).ToHaveURLAsync(_webApplicationFactory.ServerAddress+"Identity/Account/Login?ReturnUrl=%2F");
      } 
    
  • Eine, um zu überprüfen, ob die Anmeldung funktioniert, wenn die falschen Anmeldedaten angegeben werden
    
     [Test]
      public async Task WhenProvidingWrongCredentials_ShouldRespondWithInvalidLoginAttempt() { 
          await Page.GotoAsync(_webApplicationFactory.ServerAddress);
          await Page.GetByLabel("Email").ClickAsync(); 
          await Page.GetByLabel("Email").FillAsync("test@test.be"); 
          await Page.GetByLabel("Email").PressAsync("Tab"); 
          await Page.GetByLabel("Password").FillAsync("ABc.123!");
          await Page.GetByRole(AriaRole.Button, new() { Name = "Log in" }).ClickAsync();
          await Expect(Page.GetByText("Invalid login attempt.")).ToBeVisibleAsync(); 
      } 
    

Als Mike den Test durchführte, sah er, dass einfach alles funktionierte. Er wollte sehen, wie die Aktionen im Test vor seinen Augen zum Leben erweckt wurden. Mike folgte der Dokumentation und entschied sich, die Datei .runsettings zu verwenden. Er konfiguriert Visual Studio, indem er auf Test > Ausführungseinstellungen konfigurieren > Solution Wide Settings auswählen > Wählen Sie die Datei .runsettings.

Bei Anwendung der Standardeinstellungen erschien der Browser und er sah, wie der Test die Aktionen ausführte. Das liegt daran, dass Playwright.LaunchOptions.Headless auf false gesetzt ist. Die Umgebungsvariable DEBUG ist auf pw:api gesetzt, um mehr Informationen über die getätigten API-Aufrufe zu erhalten.




    

    24

  

      
      pw:api

    

    chromium
    5000

      false
      msedge

Mike fügte die Umgebungsvariable PWDEBUG mit dem Wert console hinzu. Dadurch konnte er die Selektoren in der Konsole des Browsers mit Hilfe der Variable debuggen playwright

Mike hat die Umgebungsvariable PWDEBUG mit dem Wert 1 hinzugefügt, den Test ausgeführt und die Playwright Inspector geöffnet. Er benutzte die beliebte Taste F10. Mike sah die Playwright Inspector in Aktion. In diesem Testfall bemerkte er ein Problem. Der Benutzername code>admin@test.be wird bereits in einer Registrierung verwendet.

Für diesen Test wurde keine weitere Hilfe benötigt, aber er war neugierig auf ein anderes Tool namens Trace Viewer. Dieses Tool sollte bei der Diagnose und Behebung von Problemen helfen. Bei der Aufzeichnung einer Ablaufverfolgung erfasst es nach jeder Aktion einen Schnappschuss der Seite und zeichnet Netzwerkanforderungen, JavaScript-Protokolle usw. auf. Mike durchsucht die Seite BrowserContext mit IntelliSense:

Mike wollte mehr über Playwright erfahren und wie es ihm bei der Automatisierung der Benutzerauthentifizierung helfen könnte, damit er seine Produkte zum Erstellen/Bearbeiten und Auflisten testen kann. Er hat zwei Methoden gefunden, die ihm dabei helfen können. Um sich zu authentifizieren, kann Mike Anmeldeformulare ausfüllen und abschicken, wie er es bisher getan hat:


await Page.GotoAsync(_webApplicationFactory.ServerAddress);
await Page.GetByLabel("Email").ClickAsync();
await Page.GetByLabel("Email").FillAsync("test@test.be");
await Page.GetByLabel("Email").PressAsync("Tab");
await Page.GetByLabel("Password").FillAsync("ABc.123!");
await Page.GetByRole(AriaRole.Button, new() { Name = "Log in" }).ClickAsync();

Eine andere Methode ist die Wiederherstellung von Cookies und des lokalen Speichers. Da ein Test nur das tun sollte, was er angibt, gefiel ihm diese Funktionalität. Wenn es bereits einen Test gibt, der die Anmeldefunktionalität abdeckt, dann ist es nicht nötig, dieselbe Funktionalität in einem weiteren Test zu testen.

Nach einer erfolgreichen Anmeldung speicherte Mike den Status aus den Cookies und dem lokalen Speicher und verwendete ihn wieder, anstatt sich jedes Mal neu anzumelden. Die Methode BrowserContext.StorageStateAsync ist dafür hilfreich.

Playwright erwähnt auch, dass Mike die sessionStorage Ihres Browsers manipulieren kann. Die Methode Page.EvaluateAsync hilft Ihnen dabei.


string sessionStorageData = await Page.EvaluateAsync("() => JSON.stringify(window.sessionStorage)");

In der Dokumentation von Playwright hat Mike einen Code gefunden, der JavaScript ausführt, wenn die Seite initialisiert wird. Er setzt die sessionStorage, wenn die Seite geladen wird.

Mike hatte noch einen weiteren Splitter in seinem Gehirn. Er fand Vertrauen in das Schreiben und Debuggen von Tests, aber was ist mit der Ausführung in einer CI-Pipeline? Playwright bietet eine Menge Beispiele für die Verwendung einer CI-Pipeline auf Azure, GitHub oder anderen CI-Tools. Mike verwendet das Beispiel von GitHub Actions. Es ist jedoch ein Fehler aufgetreten:

The argument 'bin/Debug/net6.0/playwright.ps1' is not recognized as the name of a script file.

Eine kurze Suche im Internet und Mike fand eine Lösung. Er musste die folgende Zeile in die Testprojektdatei einfügen:


all

Er hat den Pfad zum Testprojekt dotnet6mvcEcommerce.Playwright.tests/bin/Debug/net6.0/playwright.ps1 hinzugefügt und die Powershell aktualisiert.


- run: dotnet tool update --global PowerShell

Mike hat die GitHub-Aktion erneut ausgeführt und es hat funktioniert!


name: Ecommerce Playwright Tests
on:
  push:
    branches: [ main, master ]
  pull_request:
    branches: [ main, master ]
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Setup dotnet
      uses: actions/setup-dotnet@v3
      with:
        dotnet-version: 6.0.x
    - run: dotnet tool update --global PowerShell
    - run: dotnet build
    - name: Ensure browsers are installed
      run: pwsh dotnet6mvcEcommerce.Playwright.tests/bin/Debug/net6.0/playwright.ps1 install --with-deps
    - name: Run your tests
      run: dotnet test

Fazit

Mike ist froh, dass er eine Möglichkeit hat, schnell Code aus seinen Interaktionen zu generieren. Er wird die Aufzeichnungs-, Verfolgungs- und Debugging-Funktionen nutzen, damit er mit dem Schreiben seiner Tests beginnen kann.

Playwright ist ein großartiges Tool, das einfach zu bedienen ist. Jedes Beispiel und jede Anleitung, die Mike auf der Website gefunden hat, funktioniert auch außerhalb der Box!

Ich hoffe, dass Sie, wie Mike, inspiriert werden, Playwright auszuprobieren.

Wenn Sie Feedback haben, zögern Sie nicht, mich zu kontaktieren. Wir lernen alle voneinander.

Referenzen

Verfasst von

Kristof Riebbels

Kristof is a dynamic Software Developer, Coach, and DevOps enthusiast who loves travelling, coding, and sci-fi. He's passionate about staying physically active and thrives on positive team dynamics, where collaboration results in "1+1=3." His key talent lies in effectively transmitting knowledge to ensure it resonates with his audience. Kristoff finds joy in every "aha" moment and starts his days with epic modern orchestral music, while dance and trance music keep him focused during work.

Contact

Let’s discuss how we can support your journey.