JUnit 5 for Kotlin-utviklere

1. Introduksjon

Den nylig utgitte JUnit 5 er neste versjon av det velkjente testrammeverket for Java. Denne versjonen inneholder et antall funksjoner som spesifikt retter seg mot funksjonalitet introdusert i Java 8 - det er primært bygget rundt bruk av lambdauttrykk.

I denne raske artikkelen viser vi hvor godt det samme verktøyet er jobber med Kotlin-språket.

2. Enkle JUnit 5-tester

På det aller enkleste fungerer en JUnit 5-test skrevet i Kotlin akkurat som forventet. Vi skriver en testklasse, kommenterer testmetodene våre med @Test kommentar, skriv koden vår og utfør påstandene:

class CalculatorTest {private val calculator = Calculator () @Test fun whenAdding1and3_thenAnswerIs4 () {Assertions.assertEquals (4, calculator.add (1, 3))}}

Alt her fungerer bare ut av boksen. Vi kan benytte oss av standarden @Test, @BeforeAll, @BeforeEach, @AfterEach, og @Tross alt kommentarer. Vi kan også samhandle med felt i testklassen nøyaktig det samme som i Java.

Merk at importen som kreves er forskjellig, og vi gjørpåstander ved hjelp av Påstander klasse i stedet for Påstå klasse. Dette er en standardendring for JUnit 5 og er ikke spesifikk for Kotlin.

Før vi går videre, la oss endre testnavnet og bruke det bakktick-identifikatorer i Kotlin:

@Test fun `Å legge til 1 og 3 skal være lik 4` () {Assertions.assertEquals (4, calculator.add (1, 3))}

Nå er det mye mer lesbart! I Kotlin kan vi erklære alle variabler og funksjoner ved hjelp av backticks, men det anbefales ikke å gjøre det for normale brukssaker.

3. Avanserte påstander

JUnit 5 legger til noen avanserte påstander forjobber med lambdas. Disse fungerer det samme i Kotlin som i Java, men må uttrykkes på en litt annen måte på grunn av måten språket fungerer på.

3.1. Hevder unntak

JUnit 5 legger til en påstand om når en samtale forventes å gi et unntak. Vi kan teste at en spesifikk samtale - i stedet for bare en samtale i metoden - kaster det forventede unntaket. Vi kan til og med hevde selve unntaket.

I Java vil vi gi en lambda inn i samtalen til Påstander.assertkaster. Vi gjør det samme i Kotlin, men vi kan gjøre koden mer lesbar ved å legge til en blokk til slutten av påstanden:

@Test-moro `Deling av null skal kaste DivideByZeroException` () {val unntak = Assertions.assertThrows (DivideByZeroException :: class.java) {calculator.divide (5, 0)} Assertions.assertEquals (5, exception.numerator)}

Denne koden fungerer nøyaktig det samme som Java-ekvivalenten, men er lettere å lese, siden vi ikke trenger å passere en lambda inne i parentesene der vi kaller hevder Kaster funksjon.

3.2. Flere påstander

JUnit 5 gir muligheten til utføre flere påstander samtidig, og det vil evaluere dem alle og rapportere om alle feilene.

Dette lar oss samle mer informasjon i en enkelt testkjøring i stedet for å bli tvunget til å fikse en feil bare for å treffe den neste. For å gjøre det, ringer vi Påstander.assertAlle, passerer inn et vilkårlig antall lambdas.

I Kotlin, vi må håndtere dette litt annerledes. De funksjon tar faktisk en varargs parameter av typen Kjørbar.

For øyeblikket er det ingen støtte for å automatisk kaste en lambda til et funksjonelt grensesnitt, så vi må gjøre det for hånd:

moro `Kvadraten til et tall skal være lik det tallet multiplisert i seg selv` () {Assertions.assertAll (Executable {Assertions.assertEquals (1, calculator.square (1))}, Executable {Assertions.assertEquals (4, calculator .square (2))}, kjørbar {Assertions.assertEquals (9, calculator.square (3))})}

3.3. Leverandører for sanne og falske tester

Noen ganger ønsker vi å teste at noen samtaler returnerer a ekte eller falsk verdi. Historisk ville vi beregne denne verdien og kalle hevder sant eller hevder falske som hensiktsmessig. JUnit 5 tillater at en lambda blir gitt i stedet som returnerer verdien som blir sjekket.

Kotlin lar oss passere i en lambda på samme måte som vi så ovenfor for å teste unntak. Vi kan også gi metodereferanser. Dette er spesielt nyttig når du tester returverdien til et eksisterende objekt som vi bruker her List.is Tom:

@Test fun `isEmpty skal returnere true for tomme lister` () {val list = listOf () Assertions.assertTrue (list :: isEmpty)}

3.4. Leverandører for feilmeldinger

I noen tilfeller ønsker vi det gi vår egen feilmelding skal vises på en påstandssvikt i stedet for standard.

Ofte er dette enkle strenger, men noen ganger kan det være lurt å bruke en streng som er dyr å beregne. I JUnit 5 kan vi gi en lambda for å beregne denne strengen, og det er bare kalt på feil i stedet for å bli beregnet foran.

Dette kan hjelpe få testene til å løpe raskere og redusere byggetider. Dette fungerer nøyaktig det samme som vi så før:

@Test fun `3 er lik 4` () {Assertions.assertEquals (3, 4) {" Tre tilsvarer ikke fire "}}

4. Datadrevne tester

En av de store forbedringene i JUnit 5 er innfødt støtte for datadrevne tester. Disse fungerer like bra i Kotlin, og bruk av funksjonelle kartlegginger på samlinger kan gjøre testene våre lettere å lese og vedlikeholde.

4.1. TestFactory Metoder

Den enkleste måten å håndtere datadrevne tester på er å bruke @TestFabrikk kommentar. Dette erstatter @Test kommentar, og metoden returnerer en samling av DynamicNode forekomster - vanligvis opprettet ved å ringe DynamicTest.dynamicTest.

Dette fungerer nøyaktig det samme i Kotlin, og det kan vi passere i lambda på en renere måte igjen, som vi så tidligere:

@TestFactory moro testSquares () = listOf (DynamicTest.dynamicTest ("når jeg beregner 1 ^ 2 så får jeg 1") {Assertions.assertEquals (1, calculator.square (1))}, DynamicTest.dynamicTest ("når jeg beregner 2 ^ 2 så får jeg 4 ") {Assertions.assertEquals (4, calculator.square (2))}, DynamicTest.dynamicTest (" når jeg beregner 3 ^ 2 så får jeg 9 ") {Assertions.assertEquals (9, kalkulator .square (3))})

Vi kan gjøre det bedre enn dette. Vi kan enkelt bygg listen vår ved å utføre funksjonell kartlegging på en enkel inndataliste med data:

@TestFactory moro testSquares () = listOf (1 til 1, 2 til 4, 3 til 9, 4 til 16, 5 til 25) .map {(input, forventet) -> DynamicTest.dynamicTest ("når jeg beregner $ input ^ 2 så får jeg $ forventet ") {Assertions.assertEquals (forventet, calculator.square (input))}}

Med en gang kan vi enkelt legge til flere testtilfeller til inngangslisten, og det vil automatisk legge til tester.

Vi kan også lage inngangslisten som et klassefelt og del den mellom flere tester:

private val squaresTestData = listOf (1 til 1, 2 til 4, 3 til 9, 4 til 16, 5 til 25) 
@TestFactory moro testSquares () = squaresTestData .map {(input, forventet) -> DynamicTest.dynamicTest ("når jeg beregner $ input ^ 2 så får jeg $ forventet") {Assertions.assertEquals (forventet, calculator.square (input) )}}
@TestFactory moro testSquareRoots () = squaresTestData .map {(forventet, input) -> DynamicTest.dynamicTest ("når jeg beregner kvadratroten av $ input så får jeg $ forventet") {Assertions.assertEquals (forventet, calculator.squareRoot ( inngang))}}

4.2. Parameteriserte tester

Det er eksperimentelle utvidelser til JUnit 5 for å tillate enklere måter å skrive parametriserte tester på. Disse gjøres ved hjelp av @ParameterizedTest kommentar fra org.junit.jupiter: junit-jupiter-params avhengighet:

 org.junit.jupiter junit-jupiter-params 5.0.0 

Den siste versjonen finner du på Maven Central.

De @MethodSource kommentar tillater oss å produsere testparametere ved å kalle en statisk funksjon som ligger i samme klasse som testen. Dette er mulig, men ikke opplagt i Kotlin. Vi må bruke @JvmStatic kommentar inne i a ledsagerobjekt:

@ParameterizedTest @MethodSource ("firkanter") morsom testSquares (input: Int, forventet: Int) {Assertions.assertEquals (forventet, input * input)} ledsagerobjekt {@JvmStatic fun squares () = listOf (Arguments.of (1, 1), Argumenter. Av (2, 4))}

Dette betyr også at metodene som brukes til å produsere parametere alle må være sammen siden vi kan bare ha en eneste ledsagerobjekt per klasse.

Alle de andre måtene å bruke parametrerte tester på, fungerer nøyaktig det samme i Kotlin som de gjør i Java. @CsvSource er spesielt oppmerksom her, siden vi kan bruke det i stedet for @MethodSource for enkle testdata mesteparten av tiden for å gjøre testene våre mer lesbare:

@ParameterizedTest @CsvSource ("1, 1", "2, 4", "3, 9") morsom testSquares (input: Int, forventet: Int) {Assertions.assertEquals (forventet, input * input)}

5. Merkede tester

Kotlin-språket tillater for øyeblikket ikke gjentatte kommentarer på klasser og metoder. Dette gjør bruk av koder litt mer ordentlig, slik vi er pålagt pakk dem inn i @Merker kommentar:

@Tags (Tag ("slow"), Tag ("logarithms")) @Test fun `Logg til base 2 av 8 skal være lik 3` () {Assertions.assertEquals (3.0, calculator.log (2, 8) )}

Dette kreves også i Java 7 og støttes allerede av JUnit 5.

6. Sammendrag

JUnit 5 legger til noen kraftige testverktøy som vi kan bruke. Disse fungerer nesten alle perfekt med Kotlin-språket, men i noen tilfeller med litt annen syntaks enn vi ser i Java-ekvivalenter.

Ofte er disse endringene i syntaksen lettere å lese og jobbe med når du bruker Kotlin.

Eksempler på alle disse funksjonene finner du på GitHub.


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