En guide til JMockit forventninger

1. Introduksjon

Denne artikkelen er den andre delen i JMockit-serien. Det kan være lurt å lese den første artikkelen, ettersom vi antar at du allerede er kjent med JMockits grunnleggende informasjon.

I dag går vi dypere og fokuserer på forventningene. Vi vil vise hvordan vi kan definere mer spesifikk eller generisk argumentmatching og mer avanserte måter å definere verdier på.

2. Matching av argumentverdier

Følgende tilnærminger gjelder begge for Forventninger i tillegg til Bekreftelser.

2.1. "Eventuelle" felt

JMockit tilbyr et sett med verktøyfelt for å gjøre argumentmatching mer generisk. Et av disse verktøyene er anyX Enger.

Disse vil kontrollere at en hvilken som helst verdi ble overført, og at det er en for hver primitive type (og tilsvarende innpakningsklasse), en for strenger og en "universal" av typen Gjenstand.

La oss se et eksempel:

offentlig grensesnitt ExpectationsCollaborator {String methodForAny1 (String s, int i, Boolean b); ugyldig metodeForAny2 (Long l, List lst); } @Test offentlig ugyldig test (@Mocked ExpectationsCollaborator mock) kaster Unntak {new Expectations () {{mock.methodForAny1 (anyString, anyInt, anyBoolean); resultat = "noen"; }}; Assert.assertEquals ("any", mock.methodForAny1 ("barfooxyz", 0, Boolean.FALSE)); mock.methodForAny2 (2L, ny ArrayList ()); nye FullVerifications () {{mock.methodForAny2 (anyLong, (List) any); }}; }

Du må ta hensyn til at når du bruker noen felt, må du kaste den til forventet type. Den komplette listen over felt er tilstede i dokumentasjonen.

2.2. "Med" -metoder

JMockit gir også flere metoder for å hjelpe med generisk argumentmatching. Det er de withX metoder.

Disse gir litt mer avansert matching enn anyX Enger. Vi kan se et eksempel her der vi definerer en forventning for en metode som vil bli utløst med en streng som inneholder foo, et helt tall som ikke er lik 1, et ikke-null Boolsk og enhver forekomst av Liste klasse:

offentlig grensesnitt ExpectationsCollaborator {String methodForWith1 (String s, int i); ugyldig metodeForWith2 (boolsk b, liste l); } @Test offentlig ugyldig testForWith (@Mocked ExpectationsCollaborator mock) kaster Unntak {new Expectations () {{mock.methodForWith1 (withSubstring ("foo"), withNotEqual (1)); resultat = "med"; }}; assertEquals ("med", mock.methodForWith1 ("barfooxyz", 2)); mock.methodForWith2 (Boolean.TRUE, ny ArrayList ()); nye bekreftelser () {{mock.methodForWith2 (withNotNull (), withInstanceOf (List.class)); }}; }

Du kan se den komplette listen over withX metoder på JMockits dokumentasjon.

Ta hensyn til at den spesielle med (delegat) og withArgThat (Matcher) vil bli dekket i eget underavsnitt.

2.3. Null er ikke Null

Noe som er godt å forstå før enn senere er det null brukes ikke til å definere et argument som null har blitt overført til en hån.

Faktisk, null brukes som syntaktisk sukker for å definere at ethvert objekt vil bli sendt (så det kan bare brukes for parametere av referansetype). For å spesifikt bekrefte at en gitt parameter mottar null referanse, den withNull () matcher kan brukes.

For det neste eksemplet vil vi definere oppførselen til en mock, som skal utløses når argumentene som sendes er: hvilken som helst streng, hvilken som helst liste og en null henvisning:

offentlig grensesnitt ExpectationsCollaborator {String methodForNulls1 (String s, List l); ugyldig metodeForNulls2 (streng s, liste l); } @Test offentlig ugyldig testWithNulls (@Mocked ExpectationsCollaborator mock) {new Expectations () {{mock.methodForNulls1 (anyString, null); resultat = "null"; }}; assertEquals ("null", mock.methodForNulls1 ("blablabla", ny ArrayList ())); mock.methodForNulls2 ("blablabla", null); nye bekreftelser () {{mock.methodForNulls2 (anyString, (List) withNull ()); }}; }

Legg merke til forskjellen: null betyr hvilken som helst liste og withNull () betyr a null referanse til en liste. Spesielt unngår dette behovet for å kaste verdien til den deklarerte parametertypen (se at det tredje argumentet måtte kastes, men ikke det andre).

Den eneste forutsetningen for å kunne bruke dette er at minst en eksplisitt argumentmatcher ble brukt til forventningen (enten a med metode eller en noen felt).

2.4. "Times" -feltet

Noen ganger vil vi begrense, forhindreantall påkallelser forventet for en hånet metode. For dette har JMockit de reserverte ordene ganger, minTimes og maxTimes (alle tre tillater bare ikke-negative heltall).

offentlig grensesnitt ExpectationsCollaborator {void methodForTimes1 (); ugyldig methodForTimes2 (); ugyldig methodForTimes3 (); } @Test offentlig ugyldig testWithTimes (@Mocked ExpectationsCollaborator mock) {new Expectations () {{mock.methodForTimes1 (); ganger = 2; mock.methodForTimes2 (); }}; mock.methodForTimes1 (); mock.methodForTimes1 (); mock.methodForTimes2 (); mock.methodForTimes3 (); mock.methodForTimes3 (); mock.methodForTimes3 (); nye bekreftelser () {{mock.methodForTimes3 (); minTimes = 1; maxTimes = 3; }}; }

I dette eksemplet har vi definert nøyaktig to påkallinger (ikke en, ikke tre, nøyaktig to) av methodForTimes1 () bør gjøres ved hjelp av linjen ganger = 2;.

Så brukte vi standard oppførsel (hvis det ikke er gitt noen repetisjonsbegrensning minTimes = 1; brukes) for å definere at minst en påkallelse skal gjøres for methodForTimes2 ().

Til slutt bruker minTimes = 1; etterfulgt av maxTimes = 3; vi definerte at mellom en og tre påkallelser ville forekomme methodForTimes3 ().

Ta hensyn til at begge minTimes og maxTimes kan spesifiseres for samme forventning, så lenge minTimes tildeles først. På den andre siden, ganger kan bare brukes alene.

2.5. Tilpasset argumentmatching

Noen ganger er argumentmatching ikke så direkte som bare å spesifisere en verdi eller bruke noen av de forhåndsdefinerte verktøyene (anyX eller withX).

I de tilfellene er JMockit avhengig av Hamcrest Matcher grensesnitt. Du trenger bare å definere en matcher for det spesifikke testscenariet og bruke den matcheren med en withArgThat () anrop.

La oss se et eksempel for å matche en bestemt klasse med et bestått objekt:

offentlig grensesnitt ExpectationsCollaborator {void methodForArgThat (Object o); } public class Model {public String getInfo () {return "info"; }} @Test offentlig ugyldig testCustomArgumentMatching (@Mocked ExpectationsCollaborator mock) {new Expectations () {{mock.methodForArgThat (withArgThat (new BaseMatcher () {@Override public boolean matches (Object item) {return item instanceof Model && "info"). er lik ((((Model) item) .getInfo ());} @ Override public void describeTo (Description description) {}})); }}; mock.methodForArgThat (ny modell ()); }

3. Returverdier

La oss nå se på returverdiene; husk at følgende tilnærminger bare gjelder Forventninger da ingen returverdier kan defineres for Bekreftelser.

3.1. Resultat og retur (...)

Når du bruker JMockit, har du tre forskjellige måter å definere det forventede resultatet av påkallingen av en spottet metode. Av alle tre vil vi snakke om de to første (de enkleste) som helt sikkert vil dekke 90% av hverdagsbruk.

Disse to er resultat felt og returnerer (Objekt ...) metode:

  • Med resultat felt, kan du definere en returverdi for enhver ikke-ugyldig returspottet metode. Denne returverdien kan også være et unntak som skal kastes (denne gangen fungerer for både ikke-ugyldige og ugyldige returmetoder).
    • Flere resultat feltoppgaver kan gjøres for å komme tilbake mer enn én verdi for mer enn én metodeinnkalling (du kan blande både returverdier og feil som skal kastes).
    • Den samme oppførselen oppnås når du tildeler resultat en liste eller en rekke verdier (av samme type enn returtypen til den spottede metoden, INGEN unntak her).
  • De returnerer (Objekt ...) metoden er syntaktisk sukker for å returnere flere verdier på samme tid.

Dette vises lettere med en kodebit:

offentlig grensesnitt ExpectationsCollaborator {String methodReturnsString (); int methodReturnsInt (); } @Test offentlig ugyldig testResultAndReturns (@Mocked ExpectationsCollaborator mock) {new Expectations () {{mock.methodReturnsString (); resultat = "foo"; resultat = nytt unntak (); resultat = "bar"; returnerer ("foo", "bar"); mock.methodReturnsInt (); resultat = ny int [] {1, 2, 3}; resultat = 1; }}; assertEquals ("Bør returnere foo", "foo", mock.methodReturnsString ()); prøv {mock.methodReturnsString (); fail ("Bør ikke nå hit"); } catch (Unntak e) {// NOOP} assertEquals ("Should return bar", "bar", mock.methodReturnsString ()); assertEquals ("Bør returnere 1", 1, mock.methodReturnsInt ()); assertEquals ("Should return 2", 2, mock.methodReturnsInt ()); assertEquals ("Should return 3", 3, mock.methodReturnsInt ()); assertEquals ("Bør returnere foo", "foo", mock.methodReturnsString ()); assertEquals ("Should return bar", "bar", mock.methodReturnsString ()); assertEquals ("Bør returnere 1", 1, mock.methodReturnsInt ()); }

I dette eksemplet har vi definert det for de tre første samtalene til methodReturnsString () forventet avkastning er (i rekkefølge) “Foo”, et unntak og “Bar”. Vi oppnådde dette ved hjelp av tre forskjellige oppgaver til resultat felt.

Så videre linje 14, definerte vi at for fjerde og femte samtale, “Foo” og “Bar” skal returneres ved hjelp av returnerer (Objekt ...) metode.

For methodReturnsInt () definerte vi videre linje 13 for å returnere 1, 2 og til slutt 3 ved å tilordne en matrise med de forskjellige resultatene til resultat felt og videre linje 15 vi definerte å returnere 1 ved en enkel oppgave til resultat felt.

Som du kan se er det flere måter å definere returverdier for spottede metoder.

3.2. Delegatorer

For å avslutte artikkelen skal vi dekke den tredje måten å definere returverdien: Delegat grensesnitt. Dette grensesnittet brukes til å definere mer komplekse returverdier når man definerer spottede metoder.

Vi kommer til å se et eksempel på bare forklaringen:

offentlig grensesnitt ExpectationsCollaborator {int methodForDelegate (int i); } @Test offentlig ugyldig testDelegate (@Mocked ExpectationsCollaborator mock) {new Expectations () {{mock.methodForDelegate (anyInt); resultat = ny delegat () {int delegat (int i) kaster unntak {hvis (i <3) {retur 5; } annet {kast nytt unntak (); }}}; }}; assertEquals ("Should return 5", 5, mock.methodForDelegate (1)); prøv {mock.methodForDelegate (3); fail ("Bør ikke nå hit"); } fangst (unntak e) {}} 

Måten å bruke en delegator er å opprette en ny forekomst for den og tildele den til en returnerer felt. I denne nye forekomsten bør du opprette en ny metode med samme parametere og returtype enn den spottede metoden (du kan bruke hvilket som helst navn til den). Inne i denne nye metoden, bruk hvilken implementering du vil for å returnere ønsket verdi.

I eksemplet gjorde vi en implementering der 5 skal returneres når verdien som sendes til den spottede metoden er mindre enn 3 og et unntak kastes ellers (merk at vi måtte bruke ganger = 2; slik at den andre påkallingen forventes ettersom vi mistet standardadferden ved å definere en returverdi).

Det kan virke som ganske mye kode, men i noen tilfeller vil det være den eneste måten å oppnå det resultatet vi ønsker.

4. Konklusjon

Med dette viste vi praktisk talt alt vi trenger for å skape forventninger og verifikasjoner for våre daglige tester.

Vi vil selvfølgelig publisere flere artikler på JMockit, så hold deg oppdatert for å lære enda mer.

Og som alltid, kan den fulle implementeringen av denne opplæringen bli funnet på GitHub-prosjektet.

4.1. Artikler i serien

Alle artiklene i serien:

  • JMockit 101
  • En guide til JMockit forventninger
  • JMockit avansert bruk

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