Zápis testů uživatelského rozhraní

Dokončeno

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.

  1. V editoru Visual Studio Code otevřete integrovaný terminál.

  2. 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.

  3. 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 rozhraní IWebDriver, jeho metod a konkrétních tříd

Diagram znázorňuje tři z metod, které IWebDriver poskytují: Navigate, FindElementa Close.

Tři třídy uvedené zde, ChromeDriver, FirefoxDrivera 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, FirefoxDrivera 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, FirefoxDrivera 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:

  1. Vyhledejte odkaz podle jeho id atributu a klikněte na odkaz.
  2. Vyhledejte výsledný modální režim.
  3. Zavřete modální.
  4. 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ě.