JUnit 5 til Kotlin-udviklere

1. Introduktion

Den nyligt udgivne JUnit 5 er den næste version af den velkendte testramme til Java. Denne version indeholder et antal funktioner, der specifikt målretter mod funktionalitet, der er introduceret i Java 8 - det er primært bygget op omkring brugen af ​​lambda-udtryk.

I denne hurtige artikel viser vi, hvor godt det samme værktøj er arbejder med Kotlin-sproget.

2. Enkle JUnit 5-tests

På sin meget enkle måde fungerer en JUnit 5-test skrevet i Kotlin nøjagtigt som forventet. Vi skriver en testklasse, kommenterer vores testmetoder med @Prøve kommentar, skriv vores kode og udfør påstandene:

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

Alt her fungerer bare ud af kassen. Vi kan gøre brug af standarden @Test, @BeforeAll, @BeforeEach, @AfterEach, og @Trods alt kommentarer. Vi kan også interagere med felter i testklassen nøjagtigt det samme som i Java.

Bemærk, at den krævede import er forskellig, og Det gør vipåstande ved hjælp af Påstande klasse i stedet for Hævde klasse. Dette er en standardændring for JUnit 5 og er ikke specifik for Kotlin.

Før vi går videre, lad os ændre testnavnet og bruge det bakktick-identifikatorer i Kotlin:

@Test-sjov `Tilføjelse af 1 og 3 skal være lig med 4 '() {Assertions.assertEquals (4, calculator.add (1, 3))}

Nu er det meget mere læsbart! I Kotlin kan vi erklære alle variabler og funktioner ved hjælp af backticks, men det anbefales ikke at gøre det i normale brugssager.

3. Avancerede påstande

JUnit 5 tilføjer nogle avancerede påstande omarbejder med lambdas. Disse fungerer det samme i Kotlin som i Java, men skal udtrykkes på en lidt anden måde på grund af den måde, sproget fungerer på.

3.1. Påståede undtagelser

JUnit 5 tilføjer en påstand om, hvornår et opkald forventes at give en undtagelse. Vi kan teste, at et specifikt opkald - snarere end bare ethvert opkald i metoden - kaster den forventede undtagelse. Vi kan endda hævde selve undtagelsen.

I Java ville vi give en lambda ind i opkaldet til Assertions.assertTrows. Vi gør det samme i Kotlin, men det kan vi gøre koden mere læselig ved at tilføje en blok til slutningen af ​​påstandsopkaldet:

@Test sjov `At dividere med nul skal kaste DivideByZeroException` () {val exception = Assertions.assertThrows (DivideByZeroException :: class.java) {calculator.divide (5, 0)} Assertions.assertEquals (5, exception.numerator)}

Denne kode fungerer nøjagtigt det samme som Java-ækvivalenten, men er lettere at læse, da vi ikke behøver at passere en lambda inde i parenteserne, hvor vi kalder hævder kaster fungere.

3.2. Flere påstande

JUnit 5 tilføjer evnen til udføre flere påstande på samme tid, og det vil evaluere dem alle og rapportere om alle fejlene.

Dette giver os mulighed for at samle mere information i en enkelt testkørsel i stedet for at blive tvunget til at rette en fejl kun for at ramme den næste. For at gøre det kalder vi Påstande.assertAlle, passerer et vilkårligt antal lambdas.

I Kotlin, vi skal håndtere dette lidt anderledes. Det funktion tager faktisk en varargs parameter af typen Eksekverbar.

På nuværende tidspunkt er der ingen understøttelse for automatisk at kaste en lambda til en funktionel grænseflade, så vi er nødt til at gøre det manuelt:

sjovt 'Kvadratet af et tal skal være lig med det tal, der er ganget i sig selv' () {Assertions.assertAll (Executable {Assertions.assertEquals (1, calculator.square (1))}, Executable {Assertions.assertEquals (4, calculator .square (2))}, eksekverbar {Assertions.assertEquals (9, calculator.square (3))})}

3.3. Leverandører til ægte og falske tests

Lejlighedsvis vil vi teste, at nogle opkald returnerer a rigtigt eller falsk værdi. Historisk ville vi beregne denne værdi og kalde hævder sandt eller hævder Falsk som passende. JUnit 5 tillader, at der i stedet tilvejebringes en lambda, der returnerer den værdi, der kontrolleres.

Kotlin tillader os at passere i en lambda på samme måde som vi så ovenfor for at teste undtagelser. Vi kan også videregive metodereferencer. Dette er især nyttigt, når du tester returværdien af ​​et eksisterende objekt, som vi gør her ved hjælp af Liste. Er tom:

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

3.4. Leverandører til fejlmeddelelser

I nogle tilfælde vil vi give vores egen fejlmeddelelse skal vises ved en påstandsfejl i stedet for standard.

Ofte er dette enkle strenge, men nogle gange vil vi måske bruge en streng, der er dyr at beregne. I JUnit 5 kan vi give en lambda til at beregne denne streng, og det er kun kaldt på fiasko i stedet for at blive beregnet foran.

Dette kan hjælpe få testene til at køre hurtigere og reducere byggetider. Dette fungerer nøjagtigt det samme som vi så før:

@ Test sjovt '3 er lig med 4' () {Assertions.assertEquals (3, 4) {"Tre er ikke lig med fire"}}

4. Datadrevne tests

En af de store forbedringer i JUnit 5 er native support til datadrevne tests. Disse fungerer lige så godt i Kotlin, og brugen af ​​funktionelle kortlægninger på samlinger kan gøre vores tests lettere at læse og vedligeholde.

4.1. TestFactory Metoder

Den nemmeste måde at håndtere datadrevne tests på er ved hjælp af @TestFabrik kommentar. Dette erstatter @Prøve kommentar, og metoden returnerer en samling af DynamicNode forekomster - oprettes normalt ved at ringe DynamicTest.dynamicTest.

Dette fungerer nøjagtigt det samme i Kotlin, og det kan vi passere lambda på en renere måde igen, som vi så tidligere:

@TestFactory sjov 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, calculator .square (3))})

Vi kan dog gøre det bedre end dette. Det kan vi let opbyg vores liste ved at udføre funktionel kortlægning på en simpel inputliste med data:

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

Straks kan vi nemt tilføje flere testcases til inputlisten, og det tilføjer automatisk tests.

Det kan vi også Opret inputlisten som et klassefelt og del det mellem flere tests:

private val squaresTestData = listOf (1 til 1, 2 til 4, 3 til 9, 4 til 16, 5 til 25) 
@TestFactory sjov 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 sjov testSquareRoots () = squaresTestData .map {(forventet, input) -> DynamicTest.dynamicTest ("når jeg beregner kvadratroden af ​​$ input så får jeg $ forventet") {Assertions.assertEquals (forventet, calculator.squareRoot ( input))}}

4.2. Parameteriserede tests

Der er eksperimentelle udvidelser til JUnit 5 for at give lettere måder at skrive parametriserede test på. Disse udføres ved hjælp af @ParameterizedTest kommentar fra org.junit.jupiter: junit-jupiter-params afhængighed:

 org.junit.jupiter junit-jupiter-params 5.0.0 

Den seneste version kan findes på Maven Central.

Det @MethodSource kommentar tillader os at producere testparametre ved at kalde en statisk funktion der er i samme klasse som testen. Dette er muligt, men ikke indlysende i Kotlin. Vi skal brug @JvmStatic kommentar inde i en ledsagerobjekt:

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

Dette betyder også, at de metoder, der bruges til at producere parametre, alle skal være sammen siden vi kan kun have en enkelt ledsagerobjekt pr. klasse.

Alle de andre måder at bruge parametriserede test fungerer nøjagtigt det samme i Kotlin som de gør i Java. @CsvSource er særlig opmærksom her, da vi kan bruge det i stedet for @MethodSource for enkle testdata for det meste for at gøre vores test mere læsbare:

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

5. Mærkede tests

Kotlin-sproget tillader i øjeblikket ikke gentagne kommentarer om klasser og metoder. Dette gør brugen af ​​tags lidt mere detaljeret, som vi er forpligtet til pakk dem ind i @Mærker kommentar:

@Tags (Tag ("langsom"), Tag ("logaritmer")) @Test sjov `Log til base 2 af 8 skal være lig med 3` () {Assertions.assertEquals (3.0, calculator.log (2, 8) )}

Dette kræves også i Java 7 og understøttes allerede fuldt ud af JUnit 5.

6. Resume

JUnit 5 tilføjer nogle kraftfulde testværktøjer, som vi kan bruge. Disse fungerer næsten alle perfekt sammen med Kotlin-sproget, men i nogle tilfælde med en lidt anden syntaks, end vi ser i Java-ækvivalenterne.

Ofte er disse ændringer i syntaksen lettere at læse og arbejde med, når du bruger Kotlin.

Eksempler på alle disse funktioner kan findes på GitHub.


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