In het laatste artikel heb ik gesproken over een paar ideeën en patronen, zoals het patroon van het paginaobject, dat helpt bij het schrijven van onderhoudbare UI-tests. In dit artikel bespreken we een paar geavanceerde onderwerpen die u kunnen helpen robuustere tests te schrijven en deze op te lossen wanneer ze mislukken:
Ik ga Selenium gebruiken voor de onderwerpen over browserautomatisering die in dit artikel worden besproken.
Net als het vorige artikel zijn de concepten en oplossingen die in dit artikel worden besproken van toepassing ongeacht de taal en het UI-framework dat u gebruikt. Lees het vorige artikel voordat je verder gaat, want ik zal het een paar keer naar de voorbeeldcode verwijzen. Maak je geen zorgen; ik wacht hier.
Het toevoegen Thread.Sleep
(of over het algemeen vertragingen) voelt als een onvermijdelijke hack als het gaat om UI-testen. U hebt een test die met tussenpozen mislukt en na enig onderzoek traceert u dat terug naar incidentele vertragingen in het antwoord; U navigeert bijvoorbeeld naar een pagina en kijkt of beweert iets voordat de pagina volledig is geladen en uw browserautomatiseringsraamwerk genereert een uitzondering die aangeeft dat het element niet bestaat. Een heleboel dingen zouden aan deze vertraging kunnen bijdragen. Bijvoorbeeld:
Of een mix van deze en andere problemen.
Laten we zeggen dat u een pagina hebt die normaal gesproken minder dan een seconde duurt om te laden, maar de tests die de pagina raken mislukken zo nu en dan vanwege een incidentele vertraging in reactie. Je hebt een paar opties:
Zie je, er is geen winst met willekeurige vertragingen: je krijgt of een langzame of een brosse test suite. Hier ga ik u laten zien hoe u kunt voorkomen dat u vaste vertragingen invoegt in uw tests. We zullen twee soorten vertragingen bespreken die vrijwel alle zaken moeten omvatten waarmee je te maken hebt: een mondiale vertraging toevoegen en wachten tot er iets gebeurt.
Als al uw pagina's tegelijkertijd worden geladen om te laden, wat langer is dan verwacht, zullen de meeste tests mislukken vanwege een te laat antwoord. In gevallen zoals deze kunt u Implicit Waits gebruiken:
Een impliciete wachttijd is om WebDriver te vragen de DOM een bepaalde tijd te pollen wanneer ze proberen een element of elementen te vinden als ze niet onmiddellijk beschikbaar zijn. De standaardinstelling is 0. Eenmaal ingesteld, wordt de impliciete wachttijd ingesteld voor de levensduur van het objectobject van WebDriver.
Dit is hoe je een impliciete wachttijd instelt:
WebDriver-stuurprogramma = nieuwe FirefoxDriver (); .. Driver.Manage () Timeouts () ImplicitlyWait (TimeSpan.FromSeconds (5));
Op deze manier vertel je Selenium om maximaal 5 seconden te wachten wanneer het een element probeert te vinden of op de pagina reageert. Dus nu kun je schrijven:
driver.Url = "http: // somedomain / url_that_delays_loading"; IWebElement myDynamicElement = driver.FindElement (By.Id ("someDynamicElement"));
in plaats van:
driver.Url = "http: // somedomain / url_that_delays_loading"; Thread.Sleep (5000); IWebElement myDynamicElement = driver.FindElement (By.Id ("someDynamicElement"));
Het voordeel van deze aanpak is dat FindElement
zal terugkeren zodra het het element vindt en wacht niet de hele 5 seconden wanneer het element eerder beschikbaar is.
Zodra impliciete wachttijd is ingesteld op uw WebDrive
het is bijvoorbeeld van toepassing op alle acties op de bestuurder; zodat je van veel af kunt komen Thread.Sleep
s in uw code.
5 seconden is een wachttijd die ik goed heb gemaakt voor dit artikel - je moet de optimale impliciete wachttijd voor je aanvraag vinden en je moet dit zo kort mogelijk laten wachten. Uit de API-documentatie:
Het is verstandig om de impliciete wachttijd te verhogen, omdat dit de testrun tijd nadelig beïnvloedt, vooral bij gebruik van langzamere locatiestrategieën zoals XPath..
Zelfs als u XPath niet gebruikt, vertraagt het gebruik van lange impliciete wachttijden uw tests, met name wanneer sommige tests echt mislukken, omdat de webbesturingsprogramma lang zal wachten voordat het uitvalt en een uitzondering genereert.
Het gebruik van impliciete wachttijd is een geweldige manier om veel hardcoded vertragingen in uw code kwijt te raken; maar je bent nog steeds in een situatie beland dat je een aantal vaste vertragingen in je code moet toevoegen omdat je wacht tot er iets gebeurt: een pagina is langzamer dan alle andere pagina's en je moet langer wachten, je bent in afwachting van een AJAX-oproep om te beëindigen of om een element op de pagina te laten verschijnen of ervan te verwijderen enz. Hier moet u expliciet op wachten.
Dus je hebt de impliciete wachttijd ingesteld op 5 seconden en het werkt voor veel van je tests; maar er zijn nog steeds enkele pagina's die soms meer dan 5 seconden nodig hebben om te laden en resulteren in falende tests.
Als een kanttekening moet je eerst onderzoeken waarom een pagina zo lang duurt voordat je de kapotte test probeert te repareren door deze langer te laten wachten. Er is mogelijk een probleem met de prestaties op de pagina dat leidt naar de rode test, in welk geval u de pagina moet repareren, niet de test.
In het geval van een trage pagina kunt u vaste vertragingen vervangen door Expliciete wachttijden:
Een expliciete wachttijd is de code die u definieert om te wachten op een bepaalde voorwaarde voordat u verder gaat in de code.
U kunt expliciete wachttijden toepassen met WebDriverWait
klasse. WebDriverWait
woont in WebDriver.Support
montage en kan worden geïnstalleerd met behulp van Selenium.Support nuget:
////// Biedt de mogelijkheid om te wachten op een willekeurige voorwaarde tijdens de uitvoering van de test. /// public class WebDriverWait: DefaultWait/// /// Initialiseert een nieuw exemplaar van de /// De WebDriver-instantie heeft gewacht.De time-outwaarde die aangeeft hoe lang te wachten op de conditie. openbare WebDriverWait (IWebDriver-stuurprogramma, TimeSpan-time-out); ///klasse. /// /// Initialiseert een nieuw exemplaar van de /// Een object dat hetklasse. /// interface gebruikt om te bepalen wanneer de tijd verstreken is.De WebDriver-instantie heeft gewacht.De time-outwaarde die aangeeft hoe lang te wachten op de conditie.EEN waarde die aangeeft hoe vaak moet worden gecontroleerd of de conditie waar is. public WebDriverWait (IClock clock, IWebDriver driver, TimeSpan timeout, TimeSpan sleepInterval);
Hier is een voorbeeld van hoe u kunt gebruiken WebDriverWait
in je tests:
driver.Url = "http: // somedomain / url_that_takes_a_long_time_to_load"; WebDriverWait wait = new WebDriverWait (stuurprogramma, TimeSpan.FromSeconds (10)); var myDynamicElement = wait.Until (d => d.FindElement (By.Id ("someElement")));
We vertellen Selenium dat we willen dat het maximaal 10 seconden op deze specifieke pagina / element wacht.
Je hebt waarschijnlijk een paar pagina's die langer duren dan je standaard impliciete wachttijd en het is geen goede codeermethode om deze code overal te blijven herhalen. Ten slotte Testcode is code. U kunt dit in plaats daarvan extraheren in een methode en deze gebruiken uit uw tests:
public IWebElement FindElementWithWait (By by, int secondsToWait = 10) var wait = new WebDriverWait (WebDriver, TimeSpan.FromSeconds (secondsToWait)); return wait.Until (d => d.FindElement (by));
Dan kunt u deze methode gebruiken als:
var slowPage = new SlowPage ("http: // somedomain / url_that_takes_a_long_time_to_load"); var element = slowPage.FindElementWithWait (By.Id ("someElement"));
Dit is een gekunsteld voorbeeld om te laten zien hoe de methode er zou kunnen uitzien en hoe deze zou kunnen worden gebruikt. Idealiter zou u alle pagina-interacties verplaatsen naar uw pagina-objecten.
Laten we nog een voorbeeld van expliciet wachten bekijken. Soms is de pagina volledig geladen, maar het element is er nog niet omdat het later wordt geladen als resultaat van een AJAX-aanvraag. Misschien is het geen element waar je op wacht, maar gewoon wachten tot een AJAX-interactie voltooid is voordat je een bewering kunt doen, bijvoorbeeld in de database. Nogmaals, dit is waar de meeste ontwikkelaars gebruik van maken Thread.Sleep
om er zeker van te zijn dat, bijvoorbeeld, dat AJAX-gesprek is voltooid en het record zich nu in de database bevindt voordat ze doorgaan naar de volgende regel van de test. Dit kan eenvoudig worden verholpen met behulp van JavaScript-uitvoering!
Met de meeste frameworks voor browserautomatisering kunt u JavaScript op de actieve sessie uitvoeren en Selenium is daarop geen uitzondering. In Selenium is er een interface genaamd IJavaScriptExecutor
met twee methoden:
////// Definieert de interface waarmee de gebruiker JavaScript kan uitvoeren. /// openbare interface IJavaScriptExecutor ////// Voert JavaScript uit in de context van het momenteel geselecteerde frame of venster. /// /// De JavaScript-code die moet worden uitgevoerd. ////// De waarde die door het script wordt geretourneerd. /// object ExecuteScript (string-script, params-object [] args); ////// Voert JavaScript asynchroon uit in de context van het momenteel geselecteerde frame of venster. /// /// De JavaScript-code die moet worden uitgevoerd. ////// De waarde die door het script wordt geretourneerd. /// object ExecuteAsyncScript (string script, params object [] args);
Deze interface wordt geïmplementeerd door RemoteWebDriver
welke de basisklasse is voor alle webdriverimplementaties. Dus op uw web driver-exemplaar kunt u bellen ExecuteScript
om een JavaScript-script uit te voeren. Hier is een methode die u kunt gebruiken om te wachten tot alle AJAX-aanroepen zijn voltooid (ervan uitgaande dat u jQuery gebruikt):
// Dit wordt verondersteld te leven in een klasse die toegang heeft tot de actieve 'WebDriver' instantie via 'WebDriver' veld / eigenschap. openbare leegte WaitForAjax (int secondsToWait = 10) var wait = new WebDriverWait (WebDriver, TimeSpan.FromSeconds (secondsToWait)); wait.Until (d => (bool) ((IJavaScriptExecutor) d) .ExecuteScript ("return jQuery.active == 0"));
Combineer de ExecuteScript
met WebDriverWait
en je kunt er vanaf Thread.Sleep
toegevoegd voor AJAX-oproepen.
jQuery.active
geeft het aantal actieve AJAX-oproepen terug geïnitieerd door jQuery; dus als het nul is, zijn er geen AJAX-aanroepen actief. Deze methode werkt uiteraard alleen als alle AJAX-aanvragen worden gestart door jQuery. Als u andere JavaScript-bibliotheken gebruikt voor AJAX-communicatie, raadpleegt u de API-documentatie voor een vergelijkbare methode of houdt u zelf AJAX-oproepen bij.
Als u expliciet wacht, kunt u een voorwaarde instellen en wachten tot deze is voltooid of totdat de time-out is verstreken. We zagen hoe we konden controleren of AJAX-aanroepen voltooid moesten worden - een ander voorbeeld is het controleren op zichtbaarheid van een element. Net als de AJAX-controle zou u een voorwaarde kunnen schrijven die controleert of een element zichtbaar is; maar daar is een eenvoudigere oplossing voor ExpectedCondition
.
Van Selenium documentatie:
Er zijn enkele algemene voorwaarden die vaak voorkomen bij het automatiseren van webbrowsers.
Als je Java gebruikt, heb je geluk omdat ExpectedCondition
klas in Java is vrij uitgebreid en heeft veel gemaksmethoden. U kunt de documentatie hier vinden.
.Netontwikkelaars hebben niet zoveel geluk. Er is nog steeds een ExpectedConditions
klasse in WebDriver.Support
montage (hier gedocumenteerd) maar het is zeer minimaal:
public sealed class ExpectedConditions ////// Een verwachting voor het controleren van de titel van een pagina. /// /// De verwachte titel, die een exacte overeenkomst moet zijn. ////// openbare statische Funcwanneer de titel overeenkomt; anders-, . /// TitleIs (stringtitel); /// /// Een verwachting voor het controleren of de titel van een pagina een hoofdlettergevoelige subtekenreeks bevat. /// /// Het verwachte fragmentfragment. ////// openbare statische Funcwanneer de titel overeenkomt; anders-, . /// TitleContains (stringtitel); /// /// Een verwachting om te controleren of een element aanwezig is op de DOM van een /// pagina. Dit betekent niet noodzakelijk dat het element zichtbaar is. /// /// De locator heeft het element gevonden. ////// De openbare statische Funczodra het zich bevindt. /// ElementExists (op locator); /// /// Een verwachting om te controleren of een element aanwezig is op de DOM van een pagina /// en zichtbaar is. Zichtbaarheid betekent dat het element niet alleen wordt weergegeven, maar /// heeft ook een hoogte en breedte die groter is dan 0. /// /// De locator heeft het element gevonden. ////// De openbare statische Funczodra het zich bevindt en zichtbaar is. /// ElementIsVisible (op locator);
Je kunt deze les gebruiken in combinatie met WebDriverWait
:
var wait = new WebDriverWait (driver, TimeSpan.FromSeconds (3)) var element = wait.Until (ExpectedConditions.ElementExists (By.Id ("foo")));
Zoals je kunt zien aan de hand van de klasse hierboven, kun je de titel of delen ervan controleren en voor het bestaan en de zichtbaarheid van elementen met ExpectedCondition
. De out of the box-ondersteuning in .Net kan zeer minimaal zijn; maar deze klasse is niets anders dan een verpakking om een paar eenvoudige omstandigheden. Je kunt net zo gemakkelijk andere veel voorkomende omstandigheden in een klas implementeren en ermee gebruiken WebDriverWait
van je testscripts.
Een ander juweeltje alleen voor Java-ontwikkelaars is FluentWait
. Van de documentatiepagina, FluentWait
is
Een implementatie van de wachtinterface waarvoor de time-out en het pollinginterval tijdens de vlucht zijn geconfigureerd. Elke instantie van FluentWait definieert de maximale wachttijd voor een conditie, evenals de frequentie waarmee de conditie wordt gecontroleerd. Bovendien kan de gebruiker het wachten configureren om bepaalde soorten uitzonderingen tijdens het wachten te negeren, zoals NoSuchElementExceptions bij het zoeken naar een element op de pagina.
In het volgende voorbeeld proberen we een element met id te vinden foo
op de pagina elke vijf seconden peilen gedurende maximaal 30 seconden:
// 30 seconden wachten op een element op de pagina en // controleren op aanwezigheid elke vijf seconden. Wachtwachten = nieuwe FluentWait (driver) .withTimeout (30, SECONDS) .pollingEvery (5, SECONDS) .ignoring (NoSuchElementException.class); WebElement foo = wait.until (nieuwe functie () public WebElement apply (WebDriver-stuurprogramma) return driver.findElement (By.id ("foo")); );
Er zijn twee opvallende dingen over FluentWait
: ten eerste kunt u het polling-interval opgeven dat uw testprestaties kan verbeteren en ten tweede kunt u de uitzonderingen negeren waarin u niet bent geïnteresseerd.
FluentWait
is best gaaf en het zou gaaf zijn als er ook een equivalent bestond in .Net. Dat gezegd hebbende, het is niet zo moeilijk om het te gebruiken met WebDriverWait
.
U hebt uw pagina-objecten op hun plaats, hebt een mooie, droge, onderhoudbare testcode en vermijdt ook vaste vertragingen in uw tests; maar je tests mislukken nog steeds!
De gebruikersinterface is meestal het meest gebruikte onderdeel van een standaardtoepassing: soms verplaatst u elementen op een pagina om het ontwerp van de pagina te wijzigen en soms wijzigingen in de paginastructuur op basis van vereisten. Deze wijzigingen in de pagina-indeling en het ontwerp kunnen tot veel gebroken tests leiden als u uw kiezers niet verstandig kiest.
Gebruik geen fuzzy selectors en vertrouw niet op de structuur van uw pagina.
Vaak is mij gevraagd of het ok is om een ID alleen toe te voegen aan elementen op de pagina om te testen, en het antwoord is een volmondig ja. Om onze code-eenheid testbaar te maken, maken we er veel veranderingen aan, zoals het toevoegen van interfaces en het gebruik van Dependency Injection. Testcode is code. Doe wat nodig is om uw tests te ondersteunen.
Laten we zeggen dat we een pagina hebben met de volgende lijst:
In een van mijn tests wil ik klikken op het album "Let There Be Rock". Ik zou om problemen vragen als ik de volgende selector gebruikte:
By.XPath ( "// ul [@ id = 'album-list'] / li [3] / a")
Voeg indien mogelijk een ID toe aan elementen en richt ze direct en zonder te vertrouwen op hun omringende elementen. Dus ik ga een kleine wijziging aanbrengen in de lijst:
Ik heb toegevoegd ID kaart
attributen aan ankers op basis van de unieke id van de albums, zodat we een link direct kunnen targeten zonder er doorheen te hoeven gaan ul
en li
elementen. Dus nu kan ik de brosse selector vervangen door By.Id ( "album-35")
wat gegarandeerd werkt zolang dat album op de pagina staat, wat trouwens ook een goede bewering is. Om die selector te maken zou ik uiteraard toegang moeten hebben tot de album-id van de testcode.
Het is niet altijd mogelijk om unieke id's aan elementen toe te voegen, zoals rijen in een raster of elementen in een lijst. In gevallen zoals deze kunt u CSS-klassen en HTML-gegevenskenmerken gebruiken om traceerbare eigenschappen aan uw elementen te koppelen, zodat u ze gemakkelijker kunt selecteren. Als u bijvoorbeeld twee lijsten met albums op uw pagina had, één als resultaat van een gebruikerszoekactie en een andere voor voorgestelde albums op basis van eerdere aankopen van de gebruiker, kunt u deze onderscheiden met behulp van een CSS-klasse op de ul
element, zelfs als die klasse niet wordt gebruikt voor het stylen van de lijst:
Als u liever geen ongebruikte CSS-klassen gebruikt, kunt u in plaats daarvan HTML-gegevenskenmerken gebruiken en de lijsten wijzigen in:
en:
Een van de belangrijkste redenen waarom UI-tests mislukken, is dat een element of tekst niet op de pagina wordt gevonden. Soms gebeurt dit omdat u op een verkeerde pagina terechtkomt vanwege navigatiefouten of wijzigingen in paginabenavigaties in uw website of validatiefouten. Andere keren kan dit komen door een ontbrekende pagina of een serverfout.
Ongeacht de oorzaak van de fout en of u deze op uw CI-serverlogboek of in uw bureaubladtestconsole krijgt, NoSuchElementException
(of iets dergelijks) is niet erg handig om uit te zoeken wat er mis ging, toch? Dus wanneer uw test mislukt, is de enige manier om de fout op te lossen het opnieuw uitvoeren en bekijk deze als deze mislukt. Er zijn een paar trucjes die u zouden kunnen besparen van het opnieuw uitvoeren van uw langzame UI-tests voor het oplossen van problemen. Een oplossing hiervoor is om een screenshot te maken wanneer een test mislukt, zodat we hier later naar terug kunnen verwijzen.
Er is een interface in Selenium genoemd ITakesScreenshot
:
////// Definieert de interface die wordt gebruikt om schermopnamen van het scherm te maken. /// openbare interface ITakesScreenshot ////// Krijgt een /// ///object dat de afbeelding van de pagina op het scherm vertegenwoordigt. /// /// EEN Screenshot GetScreenshot ();object met de afbeelding. ///
Deze interface wordt geïmplementeerd door klassen van webstuurprogramma's en kan als volgt worden gebruikt:
var screenshot = driver.GetScreenshot (); screenshot.SaveAsFile ("", ImageFormat.Png);
Op deze manier, wanneer een test mislukt omdat je op een verkeerde pagina zit, kun je het snel achterhalen door het vastgelegde screenshot te controleren.
Zelfs het maken van screenshots is niet altijd voldoende. Het is bijvoorbeeld mogelijk dat u het element ziet dat u op de pagina verwacht, maar de test slaagt er nog steeds niet in het te vinden, misschien vanwege de verkeerde selector die leidt tot onsuccesvolle opzoeking van elementen. Dus in plaats van (of als aanvulling op) de schermafbeelding, zou je ook de paginabron kunnen vastleggen als html. Er is een Pagina bron
eigendom op IWebDriver
interface (die wordt geïmplementeerd door alle webdrivers):
////// Hiermee wordt de bron van de pagina opgehaald die het laatst door de browser is geladen. /// ////// Als de pagina na het laden is gewijzigd (bijvoorbeeld door JavaScript) ///, is er geen garantie dat de geretourneerde tekst die van de gewijzigde pagina is. /// Raadpleeg de documentatie van het specifieke stuurprogramma dat wordt gebruikt om /// te bepalen of de geretourneerde tekst de huidige staat van de pagina /// of de laatst verzonden tekst van de webserver weerspiegelt. De geretourneerde paginabron is een ///-weergave van de onderliggende DOM: verwacht niet dat deze wordt geformatteerd /// of escaped op dezelfde manier als het antwoord dat wordt verzonden vanaf de webserver. /// string PageSource krijg;
Net zoals we deden met ITakesScreenshot
je zou een methode kunnen implementeren die de paginabron grijpt en deze voortzet naar een bestand voor latere inspectie:
File.WriteAllText ("", driver.PageSource);
U wilt niet echt screenshots en paginabronnen maken van alle pagina's die u bezoekt en voor de slaagtests; anders zul je door duizenden moeten gaan als er iets mis gaat. In plaats daarvan moet u ze alleen vastleggen als een test mislukt of als u meer informatie nodig hebt voor het oplossen van problemen. Om vervuiling van de code met te veel try-catch-blokken te voorkomen en codeduplicaties te voorkomen, moet u al uw element-lookups en -beweringen in één klasse plaatsen en deze omsluiten met try-catch en vervolgens de screenshot en / of paginabron in het catch-blok vastleggen . Hier is een stukje code dat je zou kunnen gebruiken voor het uitvoeren van acties tegen een element:
public void Execute (By by, Actionactie) try var element = WebDriver.FindElement (by); Actie (element); vangst var capturer = nieuwe Capturer (WebDriver); capturer.CaptureScreenshot (); capturer.CapturePageSource (); gooien;
De Capturer
klasse kan worden geïmplementeerd als:
public class Capturer public static string OutputFolder = Path.Combine (AppDomain.CurrentDomain.BaseDirectory, "FailedTests"); private readonly RemoteWebDriver _webDriver; public Capturer (RemoteWebDriver webDriver) _webDriver = webDriver; public void CaptureScreenshot (string fileName = null) var camera = (ITakesScreenshot) _webDriver; var screenshot = camera.GetScreenshot (); var screenShotPath = GetOutputFilePath (bestandsnaam, "png"); screenshot.SaveAsFile (screenShotPath, ImageFormat.Png); public void CapturePageSource (string fileName = null) var filePath = GetOutputFilePath (bestandsnaam, "html"); File.WriteAllText (filePath, _webDriver.PageSource); private string GetOutputFilePath (string fileName, string fileExtension) if (! Directory.Exists (OutputFolder)) Directory.CreateDirectory (OutputFolder); var windowTitle = _webDriver.Title; fileName = bestandsnaam ?? string.Format ("0 1. 2", windowTitle, DateTime.Now.ToFileTime (), fileExtension) .Replace (':', '.'); var outputPath = Path.Combine (OutputFolder, bestandsnaam); var pathChars = Path.GetInvalidPathChars (); var stringBuilder = new StringBuilder (outputPath); foreach (var item in pathChars) stringBuilder.Replace (item, '.'); var screenShotPath = stringBuilder.ToString (); retourneer screenShotPath;
Deze implementatie blijft de screenshot- en HTML-bron behouden in een map met de naam FailedTests naast de tests, maar u kunt deze wijzigen als u ander gedrag wilt.
Hoewel ik alleen methoden toonde die specifiek zijn voor Selenium, bestaan er soortgelijke API's in alle automatiseringsraamwerken die ik ken en die gemakkelijk kunnen worden gebruikt.
In dit artikel hebben we gesproken over een paar tips en trucs voor het testen van gebruikersinterfaces. We hebben besproken hoe u een brosse en langzame UI-testsuite kunt voorkomen door vaste vertragingen in uw tests te voorkomen. Vervolgens hebben we besproken hoe brosse selectors en tests kunnen worden voorkomen door verstandig keuzes te maken voor kiezers en hoe u uw UI-tests kunt debuggen wanneer ze falen.
Het merendeel van de code in dit artikel is te vinden in de voorbeeldrepository van MvcMusicStore die we in het vorige artikel hebben gezien. Het is ook vermeldenswaard dat veel code in de MvcMusicStore is geleend van de Seleno-codebase, dus als je veel coole trucs wilt zien, zou je Seleno willen uitzoeken. Disclaimer: ik ben mede-oprichter van de TestStack-organisatie en een bijdrager op Seleno.
Ik hoop dat wat we in dit artikel hebben besproken u helpt bij het testen van uw gebruikersinterface.