Funkční testování – chybějící vrchol pyramidy (WebExpo 2016)

Post on 09-Jan-2017

1,785 views 2 download

transcript

Funkční testováníchybějící vrchol pyramidy

WebExpo

24. září 2016, Praha

Ondřej Machulda

@OndraM

Zdroj: https://commons.wikimedia.org/wiki/File:Bicycle_diagram-unif.svg, autor Fiestoforo, licence CC BY 3.0

Web si můžeme představit jako kolo – mnoho různých malých částí, které do sebe musí zapadnout. Co ale ve výsledku hlavně chceme je, aby se na něm dalo jezdit.Během vývoje jej ale netestujeme až celé, ale začínáme od nejmenších částí.

Zdroj: http://shop.toddmclellan.com/product/disassembled-bike

Proč od nejmenších částí? U nich umíme snadno definovat, jak se mají samostatně chovat a je zpravidla možné snadno otestovat, jestli se to tak chová. Například jako dílek řetězu a jeho mechanické vlastnosti. U software jsou to např. vstupy metody a očekávané výstupy. Vlastnosti, které chceme od testů shrnuje FIRST princip.

FastIsolatedRepeatableSelf-validatingTimely

Testy musí být co nejvíce FIRST!Fast – musí proběhnout rychle. Chceme rychlou zpětnou vazbu. Rychlejší testy budeme častěji spouštět. Rychlejší testy budeme raději psát a raději udržovat. Isolated – Testy na sobě nezávisí, ani nezávisí na pořadí spouštění, nenastavují si vzájemně podmínky (globální stav) s kterými další test počítá.Repeatable – Pokaždé stejný výsledek, stabilní, deterministické.Self-validating – Test sám jednoznačně pozná, jestli prošel nebo ne. Není třeba člověka, aby to ověřil.Timely – Napsané spolu s kódem (nebo nejlépe před).

Unit testy jsou nástroj pro návrh

Unit testy nesmíme brát jen jako metodu detekce chyb, možná důležitější je, že jsou i nástroj pro návrh. Zejména při test-driven developmentu (TDD) nám unit testy pomáhají zvyšovat vnitřní kvalitu kódu (= udržovatelnost, rozšiřitelnost, znovupoužitelnost, čitelnost...). Testovatelnost a dobrý a kvalitní kód jdou ruku v ruce.

Integrační testy

Zdroj: https://blogs.msdn.microsoft.com/africaapps/2013/09/11/integration-testing-on-steroids/

|

Nejde ale testovat jen nejmenší izolované část – je třeba další vrstvu testů: integrační. Ty testují spojení a komunikaci skupiny dvou či více komponent/objektů. U kola třeba, že řetěz zapadá do ozubeného kola; brzdové páčky jdou zmáčknout, plášť jde nasadit na ráfek...

Funkční systémové testy(alias end-to-end / GUI testy)

Zdroj: http://www.gianlucagimini.it/prototypes/velocipedia.html, autor Gianluca Gimini

Při výrobě kola si můžeme na konci linky říct, že to je asi OK. Ale když chceme mít jistotu, že funguje a že do sebe vše zapadlo, tak se na kole projedeme, přehodíme, zabrzdíme... Tedy nad celým systémem (= sestavené kolo/nasazená aplikace) ověříme hlavní funkcionalitu. Tyto testy jsou nenahraditelné – žádné jiné nevidí aplikací z pohledu zákazníka. Je to pro nás výstupní kontrola kvality, dále už je totiž až samotný zákazník, a to je už obvykle pozdě.

Testovací zmrzlina

Zdroj: https://watirmelon.blog/2012/01/31/introducing-the-software-testing-ice-cream-cone/, autor Alister Scott

Business

Můžeme si ale říci, že tedy budeme testovat věci hlavně z pohledu businessu: hlavně manuální a funkční testy a unit testům nebudeme věnovat pozornost. Jenomže vyšší vrstvy testů jsou méně FIRST, zpomalí nám vývoj, budeme při chybě dostávat pomalou zpětnou vazby a nijak nám ani nepomohou s interní kvalitou kódu.

Testovací zmrzlina

Zdroj: https://watirmelon.blog/2012/01/31/introducing-the-software-testing-ice-cream-cone/, autor Alister Scott

Business

Testovací zmrzlina je antipattern – tak by struktura testů vypadat neměla.

Testovací pyramida

5 %

15 %

80 %

Čas

& ná

klad

y

FIRS T

Lepší je mít složení testů jako pyramida. Protože čím nižší vrstva, tím více FIRST. Naopak čím vyšší, tím dražší a pomalejší péče o testy je. Proto by měly být základ UT, zatímco funkční testy jsou „drahé“ a měl by se jim věnovat jenom zlomek času. Nicméně neměly by chybět – podobně jako by u jízdního kola bylo špatné jej na konci netestovat vůbec.

Zdroj: https://commons.wikimedia.org/wiki/File:Brass_scales_with_flat_trays_balanced.png, autor Toby Hudson, licence CC-BY-SA-3.0

Ne v každé situaci je ale třeba funkční testy mít. Hodí se určitě, když máme vlastní aplikaci, která se dlouhodobě rozvíjí. Nebo alespoň znovupoužitelné jádro aplikace (e-shopu, CMS...). Naopak pokud děláte jednorázové prezentační weby, byla by to asi zbytečná práce. A pokud nemáte žádné testy a chcete začít testovat, začněte od unit testů!

Selenium – opensource knihovna pro automatizované ovládání browserů. Zero-config instalace, Selenium server je javové jarko.

Navíc protokol, který Selenium používá (WebDriver), je připravovaný W3C standard a v prohlížečích jej tak svorně implementují přímo výrobci browserů.

C#

Selenium není vázané na platformu ani na jazyk – a má také knihovny pro různé jazyky. Pro psaní funkčních testů je dobré si nezvětšovat technologický stack a držet se stejné platformy, jako je naše testovaná aplikace.

Navíc funkční testy nepíšeme tak často (viz testovací pyramida) – čili je třeba je psát v technologii kterou známe a se kterou běžně pracujeme.

BDDBDD

Behat + Behat + MinkMink

BDD-flavored

Codeception

Tradiční xUnit-style

PHPUnit PHPUnit Selenium2TestSelenium2Test

CaseCase

PHPUnit +php-webdriver

V PHP je více možností, jak funkční testy psát. Doporučuji buďto Codeception (kde je formát zápisu inspirován BDD), nebo pokud vám více sedí tradiční xUnit styl či již máte unit testy v PHPUnitu (jako my), tak použít ten spolu s knihovnou facebook/php-webdriver.

Naše rutina v

Funkční testy v Jobs.cz jsou součástí naší rutiny. Jak to u nás probíhá?

Naše rutina v

1. Nová (ale stabilní) funkcionalita

Funkční testy píšeme až když je nová feature „businessově zvalidovaná“ – už se ví, že z pohledu businessu i třeba UX funguje, jak má. Zkrátka až když je v takovém stavu, že se co den nemění. Navíc jdeme dělat zase nějakou jinou funkcionalitu a u této nechceme, aby se nám rozbíjela.

Naše rutina v

1. Nová (ale stabilní) funkcionalita

2. Stanoví se scénáře

Poté si produkťák a vývojář řeknou, co jsou důležité scénáře, které má v nové funkcionalitě smysl testovat. Vývojář navíc ví, kde cítí nejvyšší rizika. Hlavně je třeba, aby se psaly funkční testy jen na skutečně end-to-end scénáře a ne na to, co jde otestovat na nižší vrstvě. Funkční testy jsou nejpomalejší, nejdražší a nepomohou nám s kvalitou kódu. Musí se s nimi šetřit!

Naše rutina v

1. Nová (ale stabilní) funkcionalita

2. Stanoví se scénáře

3. Vývojář píše funkční testy

Za kvalitu softwaru je odpovědný vývojář, ne QA oddělení či tým testerů. Testy jsou kód a je třeba na ně uplatňovat stejné nároky na softwarové inženýrství, jako na jiný kód – mají být first class citizen. Jinak skončíme s pomalou a nespolehlivou sadou testů, kterým nebudeme věřit a brzy je vypneme a zahodíme.

Ukázka testu, kde je vidět, co například Selenium umí: přejít na URL, načítat elementy a zjistit jejich přítomnost (např. přes CSS selektor, xPath); pracovat s formuláři; načíst meta title; načíst text z elementů... ale i další třeba změnit velikost okna, pustit javascript, pracovat s historií prohlížeče apod.

Ukázka má ale plno problémů – například duplikace kódu (DRY), selektorů a vůbec pod-scénářů, které se mohou opakovat v několika testech.

Pomoci nám může Martin Fowler!

Martin Fowler to the rescue!

Page Object

… a návrhový vzor Page Object. Ten nám říká, že interakce s prvky UI webové stránky by měla probíhat skrze abstrakci – což bude objekt s metodami, které kopírují strukturu a interakci poskytovanou z UI. Z pohledu scénáře testu totiž chceme interagovat s rozhraním, které poskytuje stránka uživateli – ne s jeho implementací.

Zde je to samé jako předtím, ale za využití Page Objectů: instanciujeme si dvě třídy, do kterých je vyčleněna předchozí implementace, která byla přímo v testu. Nemáme tu tak žádné selektory a přímá volání WebDriveru. Což je také jediný způsob, jak testy udělat dlouhodobě udržovatelné...

Naše rutina v

1. Nová (ale stabilní) funkcionalita

2. Stanoví se scénáře

3. Vývojář píše funkční testy

4. Vlastní test-runner

Testy máme v PHPUnitu, je ale třeba integrace s knihovnou php-webdriver: spustit a nastavit prohlížeč, paralelizaci, ukládat screenshoty při chybě atd. Plus chceme, aby to vývojář mohl začít lokálně používat během minuty a bylo pro něj co nejsnazší: proto jsme si udělali vlastní test-runner.

$ composer require lmc/steward

$ java -jar selenium-server-standalone-2.53.1.jar &

$ vendor/bin/steward run staging firefox

Steward 2.0.0-DEV is running the tests... Just for you <3!

[2016-09-21 12:36:29] Waiting (running: 3, queued: 1, done: 0)

...

[2016-09-21 12:36:49] Waiting (running: 0, queued: 0, done: 4 [passed: 4])

[2016-09-21 12:36:50] All testcases done

[OK] Testcases executed: 4 (passed: 4)

github.com/lmc-eu/steward

Steward je open-source (viz github) CLI tool, instaluje se jednoduše přes Composer a usnadňuje nám plno věcí. Spouštění testů je pak jednoduché: na pozadí se spustí jar selenium serveru. Pak spustíme Stewarda – řekneme, jaké prostředí a jaký prohlížeč. A už není třeba nic dalšího (když máme Firefox)!

github.com/lmc-eu/steward

Steward také generuje přehled výsledků testů (a to i během toto, co testy běží, takže třeba na CI serveru se dá snadno podívat, v jakém stavu běžící test build je).

Naše rutina v

1. Nová (ale stabilní) funkcionalita

2. Stanoví se scénáře

3. Vývojář píše funkční testy

4. Vlastní test-runner

5. Automatické spouštění na CI

Testy se musí samy automatizovaně spouštět – jinak to nemá smysl. Navíc je třeba rychlá odezva při chybě, takže ideálně poté, co se vám zbuilduje a nasadí nová verze, tak by se měly samy pustit také funkční testy. U nás je pouštíme na Jenkins CI serveru.

Spouštění na CI serveru

+ Xvf

BrowserStack SauceLabs TestingBot

Na CI serveru můžeme testy spouštět buď v nativním prohlížeči (nainstalovaném přímo v systému) a schovaném do Xvf, nebo přes Docker, nebo v cloudových službách, kde máme na výběr z obrovské škály verzí operačních systémů a prohlížečů (ale je to zase drahé). Je možné využít nějakou kombinaci tohoto, a spouštět v cloudu třeba jen nějaké testy nebo jen někdy.

Naše rutina v

1. Nová (ale stabilní) funkcionalita

2. Stanoví se scénáře

3. Vývojář píše funkční testy

4. Vlastní test-runner

5. Automatické spouštění na CI

6. Continuous deployment

Funkční testy jsou nezbytná součást continuous deployment pipeline: mergneme do masteru, spustí se automatický build a funkční testy nad tím – když i ty projdou, build se automaticky nasadí na produkci bez manuálního zásahu. To ve výsledku zrychluje vývoj, time to market a šetří peníze, protože se na chyby nepřichází až na produkci, takže se i levněji opravují.

Takže:

Testy chceme mít co nejvíce FIRST

Struktura testů by měla být pyramida

Nemusí být složité psát a udržovat funkční testy

Selenium, Steward, Page Object

Continuous integration, continuous deployment

Udělejte z funkčních testů rutinu i u vás!

Ondřej Machulda

@OndraM

Funkční testy jsou samozřejmá součást vývoje našich produktů a nedovedeme si život bez nich už ani představit. Takže pokud to dává smysl pro i váš produkt, zvažte, jestli to také nezkusit – cesty tu jsou a možná budete mít klidnější spánek a méně produkčních incidentů.