Geautomatiseerd testen met Playwright, NUnit en Azure Pipelines

Utomated Testing With Playwright, Nunit And Azure Pipelines Blog

Hallo, iedereen! Mijn naam is Jelle, en in deze blog neem ik jullie mee in het opzetten van een professionele, betrouwbare en geautomatiseerde end-to-end testen voor 'moderne applicaties'. Nu we het gaan hebben over testen heb ik de blog voor het gemak ingedeeld in 3 secties: Arrange, Act, en Assert.


Arrange

Ik denk dat het belangrijk is om er altijd eerst voor te zorgen dat de kwaliteit van mijn software voldoet aan de normen. Daarom denk ik dat testen – vooral geautomatiseerde testen – van mijn software erg belangrijk is. Vanuit mijn ervaring weet ik dat geautomatiseerde UI test frameworks kunnen komen met ergernissen en nadelen die het hele proces van UI testen laten wankelen en inconsistent laten aanvoelen.

Als ik een unit test of back-end integratie test schrijf, en de test faalt, dan weet ik dat een van de volgende situaties klopt. Ik heb een fout gemaakt in mijn code (ik heb een bug gevonden), of ik heb een error in mijn test gemaakt. Maar ook beide scenario’s zouden aan de orde kunnen zijn.

Wanneer ik een UI test schrijf en de test faalt, dan heb ik niet dezelfde zekerheid als bij een unit test of back-end integratie test. Soms als ik de UI test opnieuw doe, dan kan het zomaar zijn dat de test het wel doet. De error zit soms in de test zelf, maar het is niet intuïtief waarom het dan faalt. Soms moet ik een thread.Sleep of zoiets engs laten toevoegen om de test te laten slagen. Als ik dit moet doen voelt het rommelig en onvoorspelbaar. Het voelt alsof ik dan aan het gissen bent.

Kanttekening: Dit probleem wordt vaak gelinkt aan het feit dat aan de ene kant te veel CPU wordt gebruikt tijdens de test, maar aan de andere kant ook door de (headless) browser tijdens de test. Hierdoor wordt de browser langzamer en mislukt de test vanwege een time-out. Browsers slurpen vaak veel CPU.

Als een gevolg hiervan, voelt de kwaliteit van mijn UI testen alsof er iets ontbreekt. Ik vertrouw mijn code meer dan test. Dit is gevaarlijk want dit zorgt ervoor dat er veel tijd wordt geïnvesteerd in UI testen om er zo voor te zorgen dat het zo soepel mogelijk verloopt net zoals bij mijn geautomatiseerde testen; of het zorgt ervoor dat de UI testen worden verbannen. Hoe dan ook, beide uitkomsten wil je voorkomen.

Zeg hallo tegen Playwright.

Playwright is een geautomatiseerd framework voor end-to-end testen. Dit betekent dat het ook UIs kan testen (vergelijkbaar met Selenium of Cypress). De beste feature is dat het recentelijk is ontworpen (sinds mei 2022), dit betekent dat het minder… laten we zeggen bagage heeft. Het focust op het testen van relevante browsers (Chrome, Firefox, en Webkit), Applicatie typen (zoals SPA), en features (uploads, downloads, etc.). Het is allemaal asynchroon, dit helpt bij de “willekeurige” time-outproblemen die ik hierboven heb benoemd.

Met Playwright kan ik testen schrijven in mijn geliefde .NET, maar er is ook support voor Java, Node.js en Python. In .NET is het geprefereerde framework om mee te testen NUnit. Maar, veel developers en testers die ik ken gebruiken liever xUnit, en dit kan ook zeker werken. Playwright is Open Source, dus ik verwacht dat er veel support gaat komen voor verschillende test frameworks. NUnit heeft echter de voorkeur omdat het zeer geschikt is om te helpen bij de verdeling van kernen om CPU-schaarste te voorkomen en om de Playwright-testen parallel uit te laten voeren.


Act

Laten we het nu in actie bekijken! Zoals altijd, bij het uitproberen van een nieuw pakket, is het een goed idee om te starten met een nieuw en klein project. We maken een nieuw NUnit project, voeren de automatisch gegenereerde test uit als een verificatietest, we zien de test slagen en voegen vervolgens Playwright toe door verwijzingen toe te voegen naar Microsoft.Playwright en Microsoft.Playwright.NUnit.

Playwright Pagetest (1)

Dus, waar kijken we nu precies naar? Als eerste zien we dat de test class nu dingen overneemt van de Pagetest class. Er zijn ook andere opties zoals ContextTest, BrowserTest en PlaywrightTest, maar PageTest is de meest logische parent class voor de meest voorkomende UI testen en scenario’s. We hebben de test natuurlijk herschreven zodat deze asynchroon is, dit moet trouwens voor elke test standaard gebeuren. Ik heb ook een simpele code lijn toegevoegd: await Page.GotoAsync(“https://playwright.dev”);. De Page object heeft locators (voor het vinden van UI elementen) en Goto- en Navigate methoden. Kortom, we kunnen het zien als de belangrijkste hub voor onze UI testen.

Zo, dit ziet er schoon uit! Met Playwright kunnen we er gewoon van uitgaan dat wanneer de test wordt uitgevoerd, de browser is opgestart. We hebben een tab in de browser en met dat tabblad kunnen we navigeren. Zeer intuïtief en gemakkelijk te leren. Natuurlijk, met voldoende wrapper-code, maken andere UI test frameworks dit soort abstractie mogelijk, maar met Playwright is het out-of-the-box!

Echter, is het niet altijd alleen maar goed nieuws. Wanneer wij de test uitvoeren krijgen we een error.

Playwright Browser

Wat is er nu aan de hand? Het is eigenlijk heel makkelijk. Playwright richt zich niet op onze daadwerkelijke browser. Het maakt gebruik van browsers specifiek voor het uitvoeren van de testen, deze moeten vooraf geïnstalleerd worden. Deze browsers kunnen ook headless zijn, dit is afhankelijk van de configuratie. Playwright maakt de installatie van deze browsers zo eenvoudig mogelijk – het heeft automatisch een (Powershell) script toegevoegd aan de buildmap, zodat we het kunnen uitvoeren. Als het script is uitgevoerd, hebben we weer een succesvolle test gedaan.

De uitgebreide documentatie helpt ons bij het schrijven van testen die cross-browser zijn, betrouwbaar en die we parallel kunnen laten lopen. Laten we dus genoeg bouwen om wat codedekking te krijgen. Maar, met al deze testen is het niet haalbaar om ze allemaal handmatig uit te voeren elke keer wanneer we een wijziging aanbrengen. Desalniettemin willen we ze keer op keer uitvoeren om ervoor te zorgen dat er geen onbedoelde achteruitgang is. Met andere woorden, we willen deze testen uitvoeren als onderdeel van een geautomatiseerde build. Laten we dus aannemen dat we met Azure DevOps werken en YAML gebruiken. De klassieke pipeline of zelfs acties in GitHub zullen op dezelfde manier werken.

Wat we nu gaan doen is onze testen uitvoeren op een Virtuele Machine - niet op een geïnstalleerde agent. Er zijn enkele voordelen aan geïnstalleerde agents, maar stel dat we de vereisten hebben dat elke nieuwe, schone machine onze testen moet kunnen uitvoeren. Wanneer we de nieuwste afbeelding van de browser binnenhalen, zouden alle testen moeten slagen. Als de nieuwste versie van de browser een functie verwijdert, wil ik dat zo snel mogelijk weten. Het is moeilijk om dat te controleren met een geïnstalleerde agent. Dus stel dat we dit gaan doen, hoe zouden we dit dan gaan opzetten?

Voordat we verder gaan naar het moeilijke deel, laten we eerst kijken naar de start van het YAML-bestand.

Playwright Yaml (1)

Niets bijzonders hier. De trigger voor deze testen moet worden uitgevoerd wanneer er een wijziging in de main wordt gemaakt. En, deze testen zullen worden uitgevoerd in .NET 6.0 - zoals ze dat ook lokaal deden - dus we moeten dat op onze agent installeren. Laten we naar het einde van het YAML-bestand gaan om te zien wat ons doel is.

Playwright Arguments (1)

Nogmaals, niets bijzonders hier. We willen alleen die testen uitvoeren die in ons testproject zitten. We kunnen de specifieke browser die moet worden gebruikt plaatsen in argumenten, regel 42.

Nu, voor het iets moeilijkere – en minder intuïtieve – gedeelte hebben we in het midden 23 regels overgeslagen. Weet je nog hoe we een script in onze buildmap moesten gebruiken om ervoor te zorgen dat de browsers zijn geïnstalleerd? Als ik mijn tests op een gloednieuwe machine uitvoer, moet ik dat script uitvoeren tijdens elke uitvoering van dit YAML-bestand. Hoe krijgen we dat werkende? Hier is helaas wel een beetje magie voor nodig.

Playwright Toolmanifest1

We willen Playwright installeren, maar we hebben een manifest nodig, omdat we een tool installatie moeten doen in deze nieuwe omgeving. We kunnen dit nu opzetten.

Vervolgens kunnen we de .NET tool Playwright installeren binnen het manifest, want we willen hier geen gebruik maken van een global .NET installatie optie. Waarom zouden we, als we bij onze volgende testen een geheel nieuwe machine hebben?

 

Vervolgens bouwen we het testproject. Met het gebouwde project hebben we een bin-map en daarbinnen hebben we het script om de browsers te installeren die Playwright nodig heeft. Natuurlijk draaien we deze keer op Linux en niet op Windows, dus het is geen Powershell-script.

Het is noodzakelijk dat het script wordt uitgevoerd in een map met een testproject erin, of in een map met een solution met een testproject erin.

Playwright Testproject1

Als we nu de hele YAML file laten draaien, dan zullen we zien dat de testen draaien op een geautomatiseerde manier. Perfect. Maar, we missen nu wel de kers op de taart. Een van de meest populaire functies van alle test frameworks die UI testen kunnen draaien is de mogelijkheid om foto’s en video’s van (mislukte) testen te zien.

Met Playwright is dat erg makkelijk op te zetten.

using Microsoft.Playwright;
using Microsoft.Playwright.NUnit;
using NUnit.Framework;
using System.Threading.Tasks;

namespace PlaywrightTest1;

public class Tests : PageTest
{
    [SetUp]
    public void Setup()
    {
    }

    public override BrowserNewContextOptions ContextOptions()
    {
        var options = base.ContextOptions() ?? new();
        options.RecordVideoDir = "videos";
        
        return options;
    }

    [Test]
    public async Task Test1()
    {
        await Page.GotoAsync("https://podcast.betatalks.nl/");
        await Page.Locator(".episode-list--play").First.ClickAsync();
        
        Assert.Pass();
    }

    [TearDown]
    public async Task TearDown()
    {
        if (Page?.Video != null)
            TestContext.AddTestAttachment(await Page.Video.PathAsync());

    }
}

In elke klasse die erft van PageTest, kunnen we een ContextOptions-methode overschrijven, wat een haakje is voor allerlei soorten configuraties. En, in de Teardown van de test kunnen we het videobestand bij de testresultaten voegen. Allemaal van code!


Assert

We hebben een NUnit testproject gecreëerd om playwright te gebruiken zodat we end-to-end-testen en UI testen kunnen schrijven. Vervolgens hebben wij die testen uitgevoerd met YAML in Azure DevOps. Nu komen we dus aan bij die ene vraag die er het meest toe doet. Kan Playwright al mijn problemen oplossen met geautomatiseerde UI testen? Het is natuurlijk lastig om zo’n vraag te beantwoorden; maar, ik durf te wedden van niet of in ieder geval niet volledig. De pipeline had een beetje magie nodig, en pipelines zijn erg slechte tovenaars. Er zijn echter een paar tekenen dat Playwright gaat bijdragen aan de zoektocht naar kwaliteit. Het voelt zeker betrouwbaarder en sterker dan andere vergelijkbare frameworks. Ik ben erg enthousiast over het vooruitzicht om Playwright te gebruiken in productiecode, dit is altijd een goed teken.

Het maken en updaten van testen moet snel zijn, en een testfout moet aangeven dat de (test) code bijgewerkt moet worden, niet dat de test opnieuw moet worden uitgevoerd. Ik heb het gevoel dat Playwright een stap in de goede richting is voor allebei de principes. Ik hoef niet meer te rommelen tijdens mijn test met het installeren van stuurprogramma’s, of rare handmatige Wait() methoden in het midden van mijn code toe te voegen, terwijl ik wacht tot de browser iets klaar heeft.

En – zoals veel huidige .NET code – is er erg weinig standaard code om te schrijven. Dit is handige om andere teamleden ervan te overtuigen die niet houden van het schrijven van testen om het deze keer wel te doen. Het kost weinig moeite en – mits het goed geschreven en onderhouden is – zullen deze testen ook veel tijd en frustratie besparen.

Kortom, ik zou zeker aanraden om Playwright uit te proberen en te onderzoeken of het ook geschikt is voor al jouw testbehoeften.


Geautomatiseerd testen met Playwright, NUnit en Azure Pipelines
Door Betabitter Jelle

Geautomatiseerd testen met Playwright, NUnit en Azure Pipelines
Gerelateerde kennis & ervaring

Geautomatiseerd testen met Playwright, NUnit en Azure Pipelines
Kom jij bij ons werken?