Zápis testů uživatelského rozhraní
V této části vám pomůžete Andy a Amita psát testy Selenium, které ověřují chování uživatelského rozhraní, které popisuje Amita.
Amita normálně spouští testy na Chromu, Firefoxu a Microsoft Edgi. Tady to samé uděláte. Agent hostovaný Microsoftem, který použijete, je předem nakonfigurovaný tak, aby fungoval s každým z těchto prohlížečů.
Načtení větve z GitHubu
V této části načtete větev z GitHubu selenium
. Pak si tuto větev můžete rezervovat nebo přepnout na tuto větev. Obsah větve vám pomůže sledovat spolu s testy, které Andy a Amita napsali.
Tato větev obsahuje projekt Space Game , se kterým jste pracovali v předchozích modulech. Obsahuje také konfiguraci Azure Pipelines, se kterými můžete začít.
V editoru Visual Studio Code otevřete integrovaný terminál.
Pokud chcete stáhnout větev pojmenovanou
selenium
z úložiště Microsoftu, přepněte na tuto větev a spusťte následujícígit fetch
příkazy:git checkout
git fetch upstream selenium git checkout -B selenium upstream/selenium
Tip
Pokud jste postupovali podle ručního testu Amita v předchozí lekci, možná jste už tyto příkazy spustili. Pokud jste je už spustili v předchozí lekci, můžete je teď spustit znovu.
Vzpomeňte si, že upstream odkazuje na úložiště Microsoft GitHub. Konfigurace Gitu vašeho projektu rozumí upstreamové vzdálené konfiguraci, protože jste tuto relaci nastavili. Nastavíte ho, když vytvoříte fork projektu z úložiště Microsoftu a naklonujete ho místně.
Tuto větev zkrátka nasdílíte do vašeho úložiště GitHub, které je označené jako
origin
.Volitelně můžete v editoru Visual Studio Code otevřít soubor azure-pipelines.yml . Seznamte se s počáteční konfigurací.
Konfigurace se podobá těm, které jste vytvořili v předchozích modulech v tomto studijním programu. Sestavuje pouze konfiguraci aplikace pro vydání. V zájmu stručnosti také vynechá triggery, ruční schválení a testy, které jste nastavili v předchozích modulech.
Poznámka:
Robustnější konfigurace může určovat větve, které se účastní procesu sestavení. Pokud chcete například ověřit kvalitu kódu, můžete testy jednotek spouštět při každém nasdílení změn v libovolné větvi. Aplikaci můžete také nasadit do prostředí, které provádí podrobnější testování. Toto nasazení ale provedete jenom v případě, že máte žádost o přijetí změn, pokud máte kandidáta na vydání verze nebo při sloučení kódu do hlavního.
Další informace najdete v tématu Implementace pracovního postupu kódu v kanálu buildu pomocí triggerů kanálů Git a GitHub a Build.
Napsání kódu testu jednotek
Amita se s radostí učí psát kód, který řídí webový prohlížeč.
Ona a Andy budou spolupracovat na psaní testů Selenium. Andy už nastavil prázdný projekt NUnit. V průběhu tohoto procesu odkazují na dokumentaci Selenium, několik online kurzů a poznámek, které vzaly, když Amita provedl testy ručně. Na konci tohoto modulu najdete další zdroje informací, které vám pomůžou procesem projít.
Pojďme se podívat na proces, který Andy a Amita používají k psaní testů. Postup můžete sledovat otevřením HomePageTest.cs v adresáři Tailspin.SpaceGame.Web.UITests v editoru Visual Studio Code.
Define the HomePageTest – třída
Andy: První věc, kterou musíme udělat, je definovat naši testovací třídu. Můžeme se rozhodnout, že se budeme řídit některou z několika zásad vytváření názvů. Říkejme nám třídu HomePageTest
. V této třídě vložíme všechny naše testy, které souvisejí s domovskou stránkou.
Andy přidá tento kód do HomePageTest.cs:
public class HomePageTest
{
}
Andy: Tuto třídu musíme označit jako public
dostupnou pro architekturu NUnit.
Přidání členské proměnné IWebDriver
Andy: Dále potřebujeme členovou proměnnou IWebDriver
.
IWebDriver
je programovací rozhraní, které používáte ke spuštění webového prohlížeče a interakci s obsahem webové stránky.
Amita: Slyšel jsem o rozhraních v programování. Můžeš mi říct víc?
Andy: Představte si rozhraní jako specifikaci nebo podrobný plán, jak se má komponenta chovat. Rozhraní poskytuje metody nebo chování dané komponenty. Rozhraní ale neposkytuje žádné podkladové podrobnosti. Vy nebo někdo jiný byste vytvořili jednu nebo více konkrétních tříd , které implementují toto rozhraní. Selenium poskytuje konkrétní třídy, které potřebujeme.
Tento diagram znázorňuje IWebDriver
rozhraní a několik tříd, které implementují toto rozhraní:
Diagram znázorňuje tři z metod, které IWebDriver
poskytují: Navigate
, FindElement
a Close
.
Tři třídy uvedené zde, ChromeDriver
, FirefoxDriver
a EdgeDriver
, každý implementuje IWebDriver
a jeho metody. Existují i další třídy, například SafariDriver
, které také implementují IWebDriver
. Každá třída ovladače může řídit webový prohlížeč, který představuje.
Andy přidá členovou proměnnou pojmenovanou driver
do HomePageTest
třídy, například tento kód:
public class HomePageTest
{
private IWebDriver driver;
}
Definování zkušebních zařízení
Andy: Chceme spustit celou sadu testů v Chromu, Firefoxu a Edgi. V NUnit můžeme použít testovací zařízení ke spuštění celé sady testů vícekrát, jednou pro každý prohlížeč, na který chceme testovat.
V NUnit použijete TestFixture
atribut k definování testovacích zařízení. Andy přidá do třídy tyto tři testovací zařízení HomePageTest
:
[TestFixture("Chrome")]
[TestFixture("Firefox")]
[TestFixture("Edge")]
public class HomePageTest
{
private IWebDriver driver;
}
Andy: Dále musíme definovat konstruktor pro naši testovací třídu. Konstruktor je volána, když NUnit vytvoří instanci této třídy. Konstruktor jako argument přebírá řetězec, který jsme připojili k našim testovacím zařízením. Kód vypadá takto:
[TestFixture("Chrome")]
[TestFixture("Firefox")]
[TestFixture("Edge")]
public class HomePageTest
{
private string browser;
private IWebDriver driver;
public HomePageTest(string browser)
{
this.browser = browser;
}
}
Andy: Přidali browser
jsme člennou proměnnou, abychom mohli použít aktuální název prohlížeče v kódu nastavení. Pojďme napsat další kód nastavení.
Definování metody nastavení
Andy: Dále musíme přiřadit naši IWebDriver
členovou proměnnou instanci třídy, která implementuje toto rozhraní pro prohlížeč, na kterém testujeme.
ChromeDriver
, FirefoxDriver
a EdgeDriver
třídy implementují toto rozhraní pro Chrome, Firefox a Edge, v uvedeném pořadí.
Pojďme vytvořit metodu s názvem Setup
, která nastaví proměnnou driver
. Atribut používáme OneTimeSetUp
k tomu, abychom NUnit řekli, aby tuto metodu spustila jednou na jedno testovací zařízení.
[OneTimeSetUp]
public void Setup()
{
}
Setup
V metodě můžeme použít switch
příkaz k přiřazení driver
členské proměnné k příslušné konkrétní implementaci na základě názvu prohlížeče. Teď přidáme tento kód.
// Create the driver for the current browser.
switch(browser)
{
case "Chrome":
driver = new ChromeDriver(
Environment.GetEnvironmentVariable("ChromeWebDriver")
);
break;
case "Firefox":
driver = new FirefoxDriver(
Environment.GetEnvironmentVariable("GeckoWebDriver")
);
break;
case "Edge":
driver = new EdgeDriver(
Environment.GetEnvironmentVariable("EdgeWebDriver"),
new EdgeOptions
{
UseChromium = true
}
);
break;
default:
throw new ArgumentException($"'{browser}': Unknown browser");
}
Konstruktor pro každou třídu ovladačů přebírá volitelnou cestu k softwaru ovladače Selenium musí řídit webový prohlížeč. Později probereme roli proměnných prostředí, které jsou zde uvedené.
V tomto příkladu EdgeDriver
konstruktor také vyžaduje další možnosti k určení, že chceme použít verzi Chromium Edge.
Definování pomocných metod
Andy: Vím, že budeme muset v průběhu testů opakovat dvě akce:
- Hledání prvků na stránce, například odkazy, na které klikneme, a modální okna, která očekáváme, že se zobrazí
- Kliknutí na prvky na stránce, například odkazy, které odhalí modální okna a tlačítko, které zavře jednotlivé modální prvky
Pojďme napsat dvě pomocné metody, jednu pro každou akci. Začneme metodou, která najde prvek na stránce.
Napsání pomocné metody FindElement
Když na stránce vyhledáte prvek, je obvykle v reakci na nějakou jinou událost, například načtení stránky nebo zadání informací uživatelem. Selenium poskytuje WebDriverWait
třídu, která umožňuje počkat na splnění podmínky. Pokud podmínka není v daném časovém období pravdivá, WebDriverWait
vyvolá výjimku nebo chybu. Třídu můžeme použít WebDriverWait
k čekání na zobrazení daného prvku a připravenosti na příjem uživatelského vstupu.
Chcete-li najít prvek na stránce, použijte By
třídu. Třída By
poskytuje metody, které umožňují najít prvek podle jeho názvu, podle názvu třídy CSS, podle značky HTML nebo v našem případě podle jeho id
atributu.
Andy a Amita kóduje pomocnou metodu FindElement
. Vypadá jako tento kód:
private IWebElement FindElement(By locator, IWebElement parent = null, int timeoutSeconds = 10)
{
// WebDriverWait enables us to wait for the specified condition to be true
// within a given time period.
return new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutSeconds))
.Until(c => {
IWebElement element = null;
// If a parent was provided, find its child element.
if (parent != null)
{
element = parent.FindElement(locator);
}
// Otherwise, locate the element from the root of the DOM.
else
{
element = driver.FindElement(locator);
}
// Return true after the element is displayed and is able to receive user input.
return (element != null && element.Displayed && element.Enabled) ? element : null;
});
}
Napsání pomocné metody ClickElement
Andy: Pojďme napsat pomocnou metodu, která klikne na odkazy. Selenium nabízí několik způsobů psaní této metody. Jedním z nich je IJavaScriptExecutor
rozhraní. Pomocí kódu programu můžeme kliknout na odkazy pomocí JavaScriptu. Tento přístup funguje dobře, protože může kliknout na odkazy bez jejich prvního posouvání do zobrazení.
ChromeDriver
, FirefoxDriver
a EdgeDriver
každý implement IJavaScriptExecutor
. Potřebujeme přetypovat ovladač do tohoto rozhraní a potom volat ExecuteScript
spuštění JavaScript click()
metody na podkladovém objektu HTML.
Andy a Amita kóduje pomocnou metodu ClickElement
. Vypadá jako tento kód:
private void ClickElement(IWebElement element)
{
// We expect the driver to implement IJavaScriptExecutor.
// IJavaScriptExecutor enables us to execute JavaScript code during the tests.
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
// Through JavaScript, run the click() method on the underlying HTML object.
js.ExecuteScript("arguments[0].click();", element);
}
Amita: Líbí se mi nápad přidat tyto pomocné metody. Zdá se, že jsou dostatečně obecné, aby používali téměř jakýkoli test. Později můžeme přidat další pomocné metody, jak je potřebujeme.
Definování testovací metody
Andy: Teď jsme připraveni definovat testovací metodu. Na základě ručních testů, které jsme spustili dříve, zavoláme tuto metodu ClickLinkById_ShouldDisplayModalById
. Osvědčeným postupem je dát testovacím metodám popisné názvy, které definují přesně to, co test dosahuje. Tady chceme kliknout na odkaz definovaný jeho id
atributem. Pak chceme ověřit, že se zobrazí správné modální okno, a to také pomocí jeho id
atributu.
Andy přidá počáteční kód pro testovací metodu:
public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
}
Andy: Než přidáme další kód, pojďme definovat, co má tento test dělat.
Amita: Mohu zvládnout tuto část. Chceme:
- Vyhledejte odkaz podle jeho
id
atributu a klikněte na odkaz. - Vyhledejte výsledný modální režim.
- Zavřete modální.
- Ověřte, že se modální režim úspěšně zobrazil.
Andy: Skvělá. Budeme také muset zvládnout několik dalších věcí. Pokud se například ovladač nepodařilo načíst, musíme ignorovat test a modální režim musíme zavřít jenom v případě, že se modální režim úspěšně zobrazil.
Po naplnění jejich kávových hrnek, Andy a Amita přidat kód do testovací metody. Používají pomocné metody, které napsali, k vyhledání prvků stránky a kliknutí na odkazy a tlačítka. Tady je výsledek:
public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
// Skip the test if the driver could not be loaded.
// This happens when the underlying browser is not installed.
if (driver == null)
{
Assert.Ignore();
return;
}
// Locate the link by its ID and then click the link.
ClickElement(FindElement(By.Id(linkId)));
// Locate the resulting modal.
IWebElement modal = FindElement(By.Id(modalId));
// Record whether the modal was successfully displayed.
bool modalWasDisplayed = (modal != null && modal.Displayed);
// Close the modal if it was displayed.
if (modalWasDisplayed)
{
// Click the close button that's part of the modal.
ClickElement(FindElement(By.ClassName("close"), modal));
// Wait for the modal to close and for the main page to again be clickable.
FindElement(By.TagName("body"));
}
// Assert that the modal was displayed successfully.
// If it wasn't, this test will be recorded as failed.
Assert.That(modalWasDisplayed, Is.True);
}
Amita: Kódování zatím vypadá skvěle. Jak ale tento test připojíme k atributům id
, které jsme shromáždili dříve?
Andy: Skvělá otázka. O to se postaráme dál.
Definování dat testovacích případů
Andy: V NUnit můžete svým testům poskytnout data několika způsoby. Tady použijeme TestCase
atribut. Tento atribut přebírá argumenty, které později předá zpět do testovací metody při spuštění. Můžeme mít více TestCase
atributů, které každý testuje jinou funkci naší aplikace. Každý TestCase
atribut vytvoří testovací případ, který je součástí sestavy, která se zobrazí na konci spuštění kanálu.
Andy tyto TestCase
atributy přidá do testovací metody. Tyto atributy popisují tlačítko Stáhnout hru , jednu z herních obrazovek a nejlepšího hráče na tabuli výsledků. Každý atribut určuje dva id
atributy: jeden pro odkaz pro kliknutí a jeden pro odpovídající modální okno.
// Download game
[TestCase("download-btn", "pretend-modal")]
// Screen image
[TestCase("screen-01", "screen-modal")]
// // Top player on the leaderboard
[TestCase("profile-1", "profile-modal-1")]
public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
...
Andy: U každého TestCase
atributu je prvním parametrem id
atribut, na který má odkaz kliknout. Druhým parametrem id
je atribut modálního okna, který očekáváme, že se zobrazí. Uvidíte, jak tyto parametry odpovídají dvěma řetězcovým argumentům v naší testovací metodě.
Amita: Vidím to. S nějakou praxí si myslím, že mohu přidat vlastní testy. Kdy uvidíme tyto testy spuštěné v našem kanálu?
Andy: Než do kanálu nasdílíme změny, nejprve ověříme, že se kód zkompiluje a spustí místně. Změny potvrdíme a nasdílíme do GitHubu a uvidíme je procházet kanálem až poté, co ověříme, že všechno funguje. Teď testy spustíme místně.