Introduksjon til ventetid

1. Introduksjon

Et vanlig problem med asynkrone systemer er at det er vanskelig å skrive lesbare tester for dem som er fokusert på forretningslogikk og ikke er forurenset med synkronisering, tidsavbrudd og samtidighetskontroll.

I denne artikkelen skal vi ta en titt på Awaitility - et bibliotek som gir et enkelt domenespesifikt språk (DSL) for asynkrone systemtesting.

Med Awaitility kan vi uttrykke våre forventninger fra systemet i en lettlest DSL.

2. Avhengigheter

Vi må legge til avhengighetsavhengighet til våre pom.xml.

De ventetid biblioteket vil være tilstrekkelig for de fleste brukssaker. I tilfelle vi ønsker å bruke proxy-baserte forhold, vi må også tilby ventetid-proxy bibliotek:

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

Du finner den siste versjonen av ventetid og ventetid-proxy biblioteker på Maven Central.

3. Opprette en asynkron tjeneste

La oss skrive en enkel asynkron tjeneste og teste den:

offentlig klasse AsyncService {privat finale int DELAY = 1000; privat finale int INIT_DELAY = 2000; private AtomicLong-verdi = nye AtomicLong (0); private Executor executor = Executors.newFixedThreadPool (4); privat flyktig boolsk initialisert = falsk; ugyld initialisere () {executor.execute (() -> {sleep (INIT_DELAY); initialized = true;}); } boolsk isInitialized () {retur initialisert; } void addValue (long val) {throwIfNotInitialized (); executor.execute (() -> {sleep (DELAY); value.addAndGet (val);}); } offentlig lang getValue () {throwIfNotInitialized (); returverdi.longValue (); } privat ugyldig søvn (int forsinkelse) {prøv {Thread.sleep (forsinkelse); } fange (InterruptedException e) {}} private void throwIfNotInitialized () {if (! initialized) {throw new IllegalStateException ("Tjenesten er ikke initialisert"); }}}

4. Testing med ventetid

La oss lage testklassen:

offentlig klasse AsyncServiceLongRunningManualTest {private AsyncService asyncService; @Før offentlig ugyldig setUp () {asyncService = ny AsyncService (); } // ...}

Testen vår sjekker om initialisering av tjenesten vår skjer innen en spesifisert tidsavbruddsperiode (standard 10s) etter at vi har ringt initialisere metode.

Denne testsaken venter bare på at tjenesteinitialiseringsstatusen endres eller kaster a ConditionTimeoutException hvis tilstandsendringen ikke skjer.

Statusen oppnås ved a Kan kalles som måler tjenesten vår med definerte intervaller (100 ms standard) etter en spesifisert innledende forsinkelse (standard 100 ms). Her bruker vi standardinnstillingene for tidsavbrudd, intervall og forsinkelse:

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

Her bruker vi avvente - en av de statiske metodene til Ventetid klasse. Den returnerer en forekomst av en TilstandFabrikk klasse. Vi kan også bruke andre metoder som gitt for å øke lesbarheten.

Standard timingparametere kan endres ved hjelp av statiske metoder fra Ventetid klasse:

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

Her kan vi se bruken av Varighet klasse, som gir nyttige konstanter for de mest brukte tidsperioder.

Vi kan også gi tilpassede tidsverdier for hver avvente anrop. Her forventer vi at initialisering vil skje maksimalt etter fem sekunder og minst etter 100 ms med avstemningsintervaller på 100 ms:

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

Det er verdt å nevne at TilstandFabrikk inneholder flere metoder som med, deretter, og, gitt. Disse metodene gjør ingenting og kommer bare tilbake dette, men de kan være nyttige for å forbedre lesbarheten til testforholdene.

5. Bruke Matchers

Awaitility tillater også bruk av hamcrest matchere for å sjekke resultatet av et uttrykk. For eksempel kan vi sjekke at vår lang verdien endres som forventet etter at du har ringt Legg til verdi metode:

asyncService.initialize (); avvente () .until (asyncService :: isInitialized); lang verdi = 5; asyncService.addValue (verdi); avvente () .until (asyncService :: getValue, equalTo (verdi));

Merk at i dette eksemplet brukte vi den første avvente ring for å vente til tjenesten er initialisert. Ellers kan den getValue metoden ville kaste en IllegalStateException.

6. Ignorer unntak

Noen ganger har vi en situasjon der en metode gir et unntak før en asynkron jobb er utført. I vår tjeneste kan det være en samtale til getValue metoden før tjenesten initialiseres.

Awaitility gir muligheten for å ignorere dette unntaket uten å mislykkes i en test.

La oss for eksempel sjekke at getValue resultatet er lik null rett etter initialisering, ignorerer IllegalStateException:

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

7. Bruke proxy

Som beskrevet i avsnitt 2, må vi ta med ventetid-proxy å bruke proxy-baserte forhold. Ideen med proxying er å gi reelle metoder som krever betingelser uten implementering av en Kan kalles eller lambdauttrykk.

La oss bruke AwaitilityClassProxy.to statisk metode for å sjekke det AsyncService er initialisert:

asyncService.initialize (); avvente () .untilCall (til (asyncService) .isInitialized (), equalTo (true));

8. Få tilgang til felt

Awaitility kan til og med få tilgang til private felt for å utføre påstander om dem. I det følgende eksemplet kan vi se en annen måte å få initialiseringsstatus for tjenesten vår:

asyncService.initialize (); avvente () .until (fieldIn (asyncService) .ofType (boolean.class) .andWithName ("initialized"), equalTo (true));

9. Konklusjon

I denne raske opplæringen introduserte vi Awaitility-biblioteket, ble kjent med dets grunnleggende DSL for testing av asynkrone systemer, og så noen avanserte funksjoner som gjør biblioteket fleksibelt og enkelt å bruke i ekte prosjekter.

Som alltid er alle kodeeksempler tilgjengelige på Github.


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