Uvod u iščekivanje

1. Uvod

Uobičajeni problem asinkronih sustava je taj što im je teško napisati čitljive testove koji su usredotočeni na poslovnu logiku i nisu zagađeni sinkronizacijama, vremenskim ograničenjima i kontrolom istodobnosti.

U ovom ćemo članku pogledati Awaitility - knjižnica koja pruža jednostavan jezik specifičan za domenu (DSL) za testiranje asinkronih sustava.

Pomoću Awaitility-a možemo izrazimo svoja očekivanja od sustava u lako čitljivom DSL-u.

2. Ovisnosti

Moramo dodati ovisnosti o očekivanjima pom.xml.

The iščekivanje knjižnica će biti dovoljna za većinu slučajeva korištenja. U slučaju da želimo koristiti uvjete temeljene na proxyju, također moramo pružiti iščekivanje-proxy knjižnica:

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

Možete pronaći najnoviju verziju iščekivanje i iščekivanje-proxy knjižnice na Maven Central.

3. Stvaranje asinkrone usluge

Napišimo jednostavnu asinkronu uslugu i testiramo je:

javna klasa AsyncService {private final int DELAY = 1000; privatni konačni int INIT_DELAY = 2000; privatna vrijednost AtomicLong = novo AtomicLong (0); privatni izvršitelj izvršitelj = Izvršitelji.newFixedThreadPool (4); privatno hlapljivo logičko ime inicijalizirano = netačno; void initialize () {executor.execute (() -> {sleep (INIT_DELAY); inicijalizirano = true;}); } boolean isInitialized () {povratak inicijaliziran; } void addValue (long val) {throwIfNotInitialized (); executor.execute (() -> {sleep (DELAY); value.addAndGet (val);}); } javni long getValue () {throwIfNotInitialized (); povratna vrijednost.longValue (); } privatno void sleep (int delay) {try {Thread.sleep (delay); } catch (InterruptedException e) {}} private void throwIfNotInitialized () {if (! initialized) {throw new IllegalStateException ("Usluga nije inicijalizirana"); }}}

4. Testiranje u očekivanju

Sada, izradimo test klasu:

javna klasa AsyncServiceLongRunningManualTest {private AsyncService asyncService; @Prije javne void setUp () {asyncService = nova AsyncService (); } // ...}

Naš test provjerava događa li se inicijalizacija naše usluge unutar određenog razdoblja isteka (zadanih 10 s) nakon poziva inicijalizirati metoda.

Ovaj testni slučaj samo čeka da se stanje inicijalizacije usluge promijeni ili baci a ConditionTimeoutException ako se ne dogodi promjena stanja.

Status dobiva a Pozivno koja anketira našu uslugu u definiranim intervalima (100 ms zadano) nakon određenog početnog kašnjenja (zadanih 100 ms). Ovdje koristimo zadane postavke za vremensko ograničenje, interval i kašnjenje:

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

Evo, koristimo čekati - jedna od statičkih metoda Dočekivanje razred. Vraća instancu a StanjeTvornica razred. Možemo se koristiti i drugim metodama poput dato radi veće čitljivosti.

Zadani vremenski parametri mogu se mijenjati statičkim metodama iz Dočekivanje razred:

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

Ovdje možemo vidjeti upotrebu Trajanje klase, koja pruža korisne konstante za najčešće korištena vremenska razdoblja.

Možemo i mi pružite prilagođene vrijednosti vremena za svaku čekati poziv. Ovdje očekujemo da će se inicijalizacija dogoditi najviše nakon pet sekundi i najmanje nakon 100 ms s intervalima anketiranja od 100 ms:

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

Vrijedno je spomenuti da StanjeTvornica sadrži dodatne metode poput s, zatim, i, dato. Ove metode ne čine ništa i samo se vraćaju ovaj, ali mogli bi biti korisni za poboljšanje čitljivosti uvjeta ispitivanja.

5. Korištenje podudaranja

Očekivanje također omogućuje upotrebu hamcrest podudarnosti za provjeru rezultata izraza. Na primjer, možemo provjeriti je li naš dugo vrijednost se mijenja kako se očekivalo nakon poziva dodatna vrijednost metoda:

asyncService.initialize (); await () .until (asyncService :: isInitialized); duga vrijednost = 5; asyncService.addValue (vrijednost); await () .until (asyncService :: getValue, jednakTo (vrijednost));

Imajte na umu da smo u ovom primjeru koristili prvi čekati nazovite da pričekate dok se usluga ne pokrene. Inače, getValue metoda bi bacila IllegalStateException.

6. Zanemarivanje iznimaka

Ponekad imamo situaciju kada metoda izbaci iznimku prije nego što se izvrši asinkroni posao. U našoj službi to može biti poziv na getValue metoda prije pokretanja usluge.

Očekivanje pruža mogućnost ignoriranja ove iznimke bez padanja na testu.

Na primjer, provjerimo je li getValue rezultat je jednak nuli odmah nakon inicijalizacije, zanemarujući IllegalStateException:

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

7. Korištenje proxyja

Kao što je opisano u odjeljku 2, moramo uključiti iščekivanje-proxy koristiti uvjete utemeljene na proxyju. Ideja proxyja je pružiti stvarne pozive metode za uvjete bez implementacije a Pozivno ili lambda izraz.

Iskoristimo AwaitilityClassProxy.to statička metoda da se to provjeri AsyncService je inicijalizirano:

asyncService.initialize (); await () .untilCall (to (asyncService) .isInitialized (), jednakTo (true));

8. Pristup poljima

Awaitility može čak pristupiti privatnim poljima kako bi na njima izvodio tvrdnje. U sljedećem primjeru možemo vidjeti još jedan način za dobivanje statusa inicijalizacije naše usluge:

asyncService.initialize (); await () .until (fieldIn (asyncService) .ofType (boolean.class) .andWithName ("Initialized"), jednakTo (true));

9. Zaključak

U ovom smo brzom vodiču predstavili knjižnicu Awaitility, upoznali se s njezinim osnovnim DSL-om za testiranje asinkronih sustava i vidjeli neke napredne značajke koje knjižnicu čine fleksibilnom i lakom za upotrebu u stvarnim projektima.

Kao i uvijek, svi primjeri koda dostupni su na Githubu.


$config[zx-auto] not found$config[zx-overlay] not found