Úvod do čakateľnosti

1. Úvod

Bežným problémom asynchrónnych systémov je, že je ťažké pre ne napísať čitateľné testy, ktoré sú zamerané na obchodnú logiku a nie sú znečistené synchronizáciami, časovými limitmi a kontrolou súbežnosti.

V tomto článku sa pozrieme na to Awaitility - knižnica, ktorá poskytuje jednoduchý jazyk špecifický pre doménu (DSL) pre testovanie asynchrónnych systémov.

S programom Awaitility môžeme vyjadrte naše očakávania od systému v ľahko čitateľnom protokole DSL.

2. Závislosti

Musíme do nášho pridať závislosti Awaitility pom.xml.

The očakávanosť knižnica bude stačiť pre väčšinu prípadov použitia. V prípade, že chceme použiť podmienky založené na proxy, tiež musíme poskytnúť awaitility-proxy knižnica:

 test org.awaitility awaitility 3.0.0 test org.awaitility awaitility-proxy 3.0.0 

Nájdete najnovšiu verziu servera očakávanosť a awaitility-proxy knižnice v Maven Central.

3. Vytvorenie asynchrónnej služby

Poďme napísať jednoduchú asynchrónnu službu a otestovať ju:

verejná trieda AsyncService {private final int DELAY = 1000; súkromný konečný int INIT_DELAY = 2000; súkromná hodnota AtomicLong = nová AtomicLong (0); private Executor Exekútor = Executors.newFixedThreadPool (4); private volatile boolean initialized = false; void initialize () {executor.execute (() -> {sleep (INIT_DELAY); initialized = true;}); } boolean isInitialized () {return initialized; } void addValue (long val) {throwIfNotInitialized (); executor.execute (() -> {sleep (DELAY); value.addAndGet (val);}); } public long getValue () {throwIfNotInitialized (); návratová hodnota.longValue (); } private void sleep (int delay) {try {Thread.sleep (delay); } catch (InterruptedException e) {}} private void throwIfNotInitialized () {if (! initialized) {throw new IllegalStateException ("Service is not initialized"); }}}

4. Testovanie s Awaitility

Teraz vytvorme testovaciu triedu:

verejná trieda AsyncServiceLongRunningManualTest {private AsyncService asyncService; @ Pred public void setUp () {asyncService = nový AsyncService (); } // ...}

Náš test kontroluje, či k inicializácii našej služby dôjde v stanovenom časovom limite (predvolene 10 s) po zavolaní na server inicializovať metóda.

Tento testovací prípad iba čaká na zmenu stavu inicializácie služby alebo hodí a ConditionTimeoutException ak nedôjde k zmene stavu.

Status získava a Vyvolávateľná ktorý dopytuje našu službu v definovaných intervaloch (predvolene 100ms) po zadanom počiatočnom oneskorení (predvolene 100ms). Tu používame predvolené nastavenia pre časový limit, interval a oneskorenie:

asyncService.initialize (); await () .until (asyncService :: isInitialized);

Tu používame čakať - jedna zo statických metód Čakateľnosť trieda. Vráti inštanciu a ConditionFactory trieda. Môžeme použiť aj iné metódy ako daný z dôvodu zvýšenia čitateľnosti.

Predvolené parametre časovania je možné zmeniť pomocou statických metód z Čakateľnosť trieda:

Awaitility.setDefaultPollInterval (10, TimeUnit.MILLISECONDS); Awaitility.setDefaultPollDelay (Duration.ZERO); Awaitility.setDefaultTimeout (Duration.ONE_MINUTE);

Tu vidíme použitie Trvanie triedy, ktorá poskytuje užitočné konštanty pre najčastejšie používané časové obdobia.

Môžeme tiež pre každú poskytnúť vlastné hodnoty časovania čakať hovor. Tu očakávame, že k inicializácii dôjde nanajvýš po piatich sekundách a minimálne po 100ms s intervalmi dotazovania 100ms:

asyncService.initialize (); await () .atLeast (Duration.ONE_HUNDRED_MILLISECONDS) .atMost (Duration.FIVE_SECONDS). s () .pollInterval (Duration.ONE_HUNDRED_MILLISECONDS) .until (asyncService :: isInitialized);

Za zmienku stojí, že ConditionFactory obsahuje ďalšie metódy ako s, potom, a, daný. Tieto metódy nič nerobia a iba sa vracajú toto, ale mohli by byť užitočné na zvýšenie čitateľnosti testovacích podmienok.

5. Používanie zhody

Awaitility tiež umožňuje použitie hamcrest porovnávače na kontrolu výsledku výrazu. Môžeme napríklad skontrolovať, či je náš dlho po volaní súboru sa hodnota podľa očakávania zmení pridaná hodnota metóda:

asyncService.initialize (); await () .until (asyncService :: isInitialized); dlhá hodnota = 5; asyncService.addValue (hodnota); await () .until (asyncService :: getValue, equalTo (hodnota));

Upozorňujeme, že v tomto príklade sme použili prvý čakať zavolajte a počkajte, kým sa služba inicializuje. Inak by getValue metóda by hodila IllegalStateException.

6. Ignorovanie výnimiek

Niekedy sa vyskytne situácia, keď metóda vyhodí výnimku skôr, ako sa vykoná asynchrónna práca. V našej službe to môže byť hovor na getValue pred inicializáciou služby.

Awaitility poskytuje možnosť ignorovať túto výnimku bez toho, aby prepadol testu.

Napríklad skontrolujeme, či getValue výsledok sa rovná nule hneď po inicializácii, ignoruje sa IllegalStateException:

asyncService.initialize (); given (). ignoreException (IllegalStateException.class) .await (). atMost (Duration.FIVE_SECONDS) .atLeast (Duration.FIVE_HUNDRED_MILLISECONDS) .until (asyncService :: getValue, equalTo (0L));

7. Používanie Proxy

Ako je opísané v časti 2, musíme zahrnúť awaitility-proxy používať podmienky založené na proxy. Myšlienkou proxy je poskytnúť skutočné volania metód na podmienky bez implementácie a Vyvolávateľná alebo lambda výraz.

Použime AwaitilityClassProxy.to statická metóda na overenie toho AsyncService je inicializovaný:

asyncService.initialize (); await () .untilCall (do (asyncService) .isInitialized (), equalTo (true));

8. Prístup k poliam

Awaitility môže dokonca získať prístup k súkromným poliam, aby na nich mohol vykonávať tvrdenia. V nasledujúcom príklade vidíme ďalší spôsob, ako získať stav inicializácie našej služby:

asyncService.initialize (); await () .until (fieldIn (asyncService) .ofType (boolean.class) .andWithName ("inicializované"), rovnáTo (pravda));

9. Záver

V tomto rýchlom výučbe sme predstavili knižnicu Awaitility, oboznámili sme sa so základným protokolom DSL pre testovanie asynchrónnych systémov a uviedli sme niektoré pokročilé funkcie, vďaka ktorým je knižnica flexibilná a ľahko sa používa v skutočných projektoch.

Všetky príklady kódov sú ako vždy k dispozícii na stránkach Github.