Hodně lidí v Pythonu používá unittest
, což je modul ze standardní knihovny,
který lidem umožňuje rychle vytáhnout nějaký ten XUnit způsob psaní testů
plný class TestNěco
, self.assertTamto()
a setUp/tearDown
tohleto. Když
je testů víc, běžně si k tomu vytáhnou nějaký namakanější test runner, třeba
nose
. Test runner je něco, co umí inteligentně spouštět testy - např. jen ty,
které od posledně selhaly, ale těch užitečných funkcí je tam víc.
Protože nose
testy spouští, umožňuje vyběhnout z XUnit stylu a nabízí spoustu
dalších triků, které ale nikdo nepoužívá, protože o nich neví. V zásadě ale
platí, že pokud chci pustit jen nějakou podmnožinu testů, existuje na to chytrý
přepínač. To mi u JS frameworků chybí. Nejspíš někdo všechny přepínače dopsal,
ale každý má pět implementací a musím na to doinstalovat npm balíček. To není
vhodné, jelikož zde se mi hodí
- konvence (kolega nemusí zjišťovat který konkrétní přepínač používám v tomto konkrétním projektu),
- pohodlí a uživatelská příjemnost (přepínač je po ruce i když ho potřebuju třikrát za život).
No a pak je tady pytest
, což je framework, který zvládne nejspíš vše co
nose
, ale navíc dává programátorům i úplně ulítlé možnosti, jak jednoduše
napsat testy. Ačkoliv se v Pythonu razí spíš "be explicit" a "no magic",
v případě testů se na oblibě pytestu ověřilo, že někdy je magie přijatelná a
užitečná. Např. v tomto případě zvyšuje deklarativnost a čitelnost testů.
Protože za pytestem stojí i člověk, který napsal PyPy (překladač Pythonu napsaný
v Pythonu), je ta magie na poměrně hluboké úrovni. Např. Python má klíčové slovo
assert
, které je ale v základu dost primitivní a umí akorát porovnat dvě
hodnoty a vyhodit obecnou chybu, pokud hodnoty nesedí. Totéž co funkce assert
v Node.js: https://nodejs.org/api/assert.html Co ale dělá pytest?
Pomocí introspekce se hrabe v mezikódu Python interpreteru a obohatí asserty tak,
aby kontextově poznaly, co porovnávají a podle toho vyhodily pěkné srovnání.
- https://pytest.org/latest/assert.html
- http://pybites.blogspot.co.at/2011/07/behind-scenes-of-pytests-new-assertion.html
Nepotřebuji tedy tahák na assert.domysliSiSvojiPorovnávacíFunkci, stačí mi používat normální opetátory a typy, které se nacházejí v jazyce. Toto žádná JS knihovna nikdy neudělá, protože jí bude chybět dostatečná introspekce do toho, co se děje.
Další věci JS knihovny okopírovat mohou, ale nedělají to a v tom je problém. Je libo feature request na parametrizovatelnost testů (což považuji za základní funkci obecného test frameworku) i s rantem o tom, jak Mocha maintaineři nové features odmítají jako nepotřebné, nechávají je vyhnít, nedělají review apod.? Prosím:
V Mocha vypadají killer features takto:
- spouští všechny testy a když někam napíšeš "only", spustíš jen ten test
- jakože-bdd přístup, který se skládá z
describe
ait
- můžeš grepovat přes popisky testů, ale konkrétní soubor s testy nespustíš (ano, když grep chytí víc popisků, spustí se víc testů)
- tuny boilerplate kódu v
before
nebobeforeEach
- když spadne test, někdy se pomalu ani nedovíš, ve kterém souboru se to odehrálo
- dokumentace úplně na hovno
- vypisuje věci barvičkami
- umí asynchronní věci, přes callbacky
V pytestu to vypadá takto:
- žádné XUnit, žádné hry na BDD, prostě jednoduché funkce s obyčejnými asserty http://pytest.org/latest/assert.html
- pomáhá odhalovat co se sakra děje http://pytest.org/latest/example/reportingdemo.html
- automatická správa stdout během testů pytest.org/latest/capture.html
- totální killer feature: koncept fixtures pro psaní závislostí jednotlivých testů http://pytest.org/latest/fixture.html
- parametrizace testů out of the box: http://pytest.org/latest/parametrize.html
- distribuované testování: http://pytest.org/latest/xdist.html
- umí spouštět jakékoliv testy Python světa včetně nepythoních pytest.org/latest/example/nonpython.html nebo testů dokumentace https://docs.python.org/3/library/doctest.html
Člověk by si řekl, že tohle všechno jde nejspíš do Mocha doplnit. Nejspíš ano. Nejspíš to žije někde na npm, má to dva commity a autor balíčku už dávno píše v Elmu, takže nové verze neřeší. Taky jde o to, že balíčky pro Mochu v zásadě řeší její nemoci a nedostatky, ne extra fičury, které potřebuje jen někdo.
Jak vypadá řešení nemocí?
https://github.com/rstacruz/mocha-clean
Toto je nejvýše hvězdičkovaný doplněk pro Mochu na GitHubu, který ji nějak doplňuje, tzn. není to jen integrace typu Mocha + React, Mocha + Mongo, Mocha + browser apod. Jak oproti tomu vypadá extra fičura?
https://github.com/tarpas/pytest-testmon/
Doplněk, který využívá code coverage k tomu, aby určil, které testy má spustit znova
a které může nechat ležet ladem. Tzn. něco, co extrémně zvyšuje produktivitu. Žádné
manuální .only
nebo otrocké grepování.
Významný problém také je, že pisatelé Mocha testů neví, že takové fičury existují a neví, že je potřebují. Výsledkem je, že
- tyhle doplňky nepíšou,
- ve větších test suites jejich testy živelně přerostou do 1000řádkových souborů plných boilerplate kódu, které se nedají ani číst, ani spouštět.
Kdyby někde zahlédli že existuje něco jako parametrizace nebo správa fixtures,
třeba by je to trklo a zkusili by to použít, psát ty testy čistěji. Ale tím, že
to po ruce nemají, tak buď testy copy-pastují, nebo si pomůžou přes forEach
a všude naplácejí nějaké funkce na sdílení assertů. Nevím, který z těch dvou
přístupů je horší. První je čitelný, ale špatně spravovatelný, druhý je nečitelný,
byť alespoň iluzorně o něco lépe spravovatelný.
No a to je můj rant na testování v JS. Dlouhodobá frustrace z toho, že se v JS
musí nejen vynalézt na tomto poli znova kolo, ale že ho ani nikdo nevynalézá.
Módní výstřelky typu AVA https://github.com/avajs/ava nikoho nespasí. Už podle
README nevidím, že by řešily cokoliv z mnou nastíněných problémů. AVA vypadá jako
Mocha s jinou syntaxí, ještě méně fičurama (tzn. bude vyžadovat nový ekosystém
ava-*
balíčků na npm) a jednou jedinou killer, což je lepší podpora pro
asynchronní programování (promises, async/await). To samozřejmě pytest nemá...
oh await! https://github.com/pytest-dev/pytest-asyncio
Možná ještě větší vedení k izolaci testů, oukej, nebudu tak zlej. Samozřejmě autoři spálili hromadu času na tom, aby to jelo se všema Babelama a Reactama a TypeScriptem, ale to nejsou fičury, které mi ušetří čas při psaní testů, to jsou šaškárny JS ekosystému, za které nemůžu a nezajímají mě. Není tam nic, co reálně ovlivňuje produktivitu, uživatelskou přívětivost a psatelnost složitějších testů.
https://twitter.com/cznodejs/status/737395185462697985
Takže abych odpověděl na tweet... Žádné 3 hlavní věci nejsou. Jsou to dvě věci.
Jedna věc je, že asserty jako jsou v pytestu (nebo deklarativnost pomocí dekorátorů, ale ty možná JS už má nebo mít bude) nikdo neudělá kvůli omezením jazyka.
Druhá věc je, že jestli AXA je následovníkem Mochy, tak JS frameworky nesměřují k jednodušší a pohodlnější práci s testy, ale k paralelizaci (thumbs up) a "frikulínství as a feature" (grumpy cat). Nikde na obzoru nevidím ani tak základní věc, jako je "namakanější spouštěč testů", což bylo něco, čím Python žil před lety a dnes je to komodita. To čím Python žije dnes - jak psát strukturovanější, spravovatelnější a čitelnější kód testů, vypadá ve srovnání s JS jako velmi vzdálené 1st world problems. Jsem smutný, že to v JS nikomu nechybí, ale chápu, že je to jako propagovat třídění odpadu v Súdánu.
Reklama: Většinu vědomostí o testování Pythonu jsem načerpal na Pyvech, srazech Python programátorů, a to především na nedávném pražském, které bylo přímo na téma testování: http://pyvo.cz/praha Pokud chcete být tak chytří jako já, choďte na Pyvo.
Souhlas :)
Možnosti pytest fixtur ještě výrazně rostou s použitím něčeho jako http://horejsek.github.io/python-pytest-data/
Osobně se divím, že to nevzniklo daleko dřív a nepoužívá to mnohem víc lidí.