Záznam přednášky: https://www.webexpo.cz/praha2016/prednaska/funkcni-testovani-chybejici-vrchol-pyramidy/
Automatické testování nejsou zdaleka jenom unit-testy - ty sice tvoří základ takzvané testovací pyramidy, ta by ale neměla zůstat nedostavěná. Přednáška o tom, kdy a jak se během vývoje věnovat také vyšší vrstvě testů - funkčnímu testování alias testům uživatelského rozhraní (end-to-end testům). A naopak v jakých situacích by to byla asi zbytečná práce.
Také popíši, jak vypadá náš rutinní proces psaní funkčních Selenium testů v Jobs.cz a ukáži několik nástrojů převážně (ale nejenom) pro PHP, které můžete při vytváření a spouštění funkčních testů v praxi využít a které vám celou práci mohou usnadnit.
2. 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í.
3. 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.
4. Fast
Isolated
Repeatable
Self-validating
Timely
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).
5. 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.
7. 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ě.
8. 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.
10. Testovací pyramida
5 %
15 %
80 %
Čas&náklady
FIRST
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.
11. 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ů!
12. 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ů.
13. 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.
14.
BDDBDD
Behat +Behat +
MinkMink
BDD-
flavored
Codeception
Tradiční xUnit-style
PHPUnitPHPUnit
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.
15. Naše rutina v
Funkční testy v Jobs.cz jsou součástí naší rutiny. Jak to u nás probíhá?
16. 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.
17. 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!
18. 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.
19. 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.
20. 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.
22. 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í.
23. 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é...
24. 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.
25. $ 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)!
26. 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).
27. 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.
28. 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.
29. 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í.
30. 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
31. 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ů.