MockK: Et hånligt bibliotek for Kotlin

1. Oversigt

I denne vejledning skal vi se på nogle af de grundlæggende funktioner i MockK-biblioteket.

2. MockK

I Kotlin er alle klasser og metoder endelige. Selvom dette hjælper os med at skrive uforanderlig kode, forårsager det også nogle problemer under testningen.

De fleste JVM-mock-biblioteker har problemer med mocking eller stubbing af sidste klasser. Selvfølgelig kan vi tilføje “åben”Nøgleord til klasser og metoder, som vi ønsker at håne. Men at skifte klasse kun for at spotte nogle koder føles ikke som den bedste tilgang.

Her kommer MockK-biblioteket, der tilbyder support til Kotlin-sprogfunktioner og -konstruktioner. MockK bygger fuldmagter til mocked klasser. Dette medfører en vis forringelse af ydeevnen, men de samlede fordele, som MockK giver os, er det værd.

3. Installation

Installation er så enkel som den kan være. Vi skal bare tilføje mockk-afhængighed til vores Maven-projekt:

 io.mockk mockk 1.9.3 test 

For Gradle skal vi tilføje det som en testafhængighed:

testImplementation "io.mockk: mockk: 1.9.3"

4. Grundlæggende eksempel

Lad os oprette en tjeneste, som vi gerne vil håne:

klasse TestableService {fun getDataFromDb (testParameter: String): String {// forespørgselsdatabase og returneringsmatchværdi} fun doSomethingElse (testParameter: String): String {return "Jeg vil ikke!" }}

Her er et eksempel på en test, der håner Testbar service:

@Test-sjov givenServiceMock_whenCallingMockedMethod_thenCorrectlyVerified () {// given val service = mockk () every {service.getDataFromDb ("Expected Param")} returnerer "Expected Output" // when val result = service.getDataFromDb ("Expected Param") // bekræft derefter {service.getDataFromDb ("Expected Param")} assertEquals ("Expected Output", result)}

For at definere det mock-objekt har vi brugt mockk () metode.

I det næste trin definerede vi vores mocks opførsel. Til dette formål har vi oprettet en hver blok, der beskriver, hvilket svar der skal returneres for hvilket opkald.

Endelig brugte vi verificere blok for at kontrollere, om mocken blev påberåbt som vi forventede.

5. Kommentareksempel

Det er muligt at bruge MockK-kommentarer til at oprette alle slags mocks. Lad os oprette en tjeneste, der kræver to forekomster af vores Testbar service:

klasse InjectTestService {lateinit var service1: TestableService lateinit var service2: TestableService fun invokeService1 (): String {return service1.getDataFromDb ("Test Param")}}

InjectTestService indeholder to felter med samme type. Det vil ikke være et problem for MockK. MockK forsøger at matche egenskaber efter navn og derefter efter klasse eller superklasse. Det også har ikke noget problem med at indsprøjte objekter i private felter.

Lad os spotte InjectTestService i en test ved hjælp af annoteringer:

klasse AnnotationMockKUnitTest {@MockK lateinit var service1: TestableService @MockK lateinit var service2: TestableService @InjectMockKs var objectUnderTest = InjectTestService () @BeforeEach fun setUp () = MockKAnnotations.init (this) // Tests here ...}

I ovenstående eksempel har vi brugt @InjectMockKs kommentar. Dette specificerer et objekt, hvor definerede mocks skal injiceres. Som standard injicerer den variabler, der endnu ikke er tildelt. Vi kan bruge @OverrideMockKs for at tilsidesætte felter, der allerede har en værdi.

MockK kræver MockKAnnotations.init (…) at blive kaldt på et objekt, der erklærer en variabel med kommentarer. For Junit5 kan den erstattes med @ExtendWith (MockKExtension :: klasse).

6. Spy

Spy tillader kun at spotte en bestemt del af en klasse. For eksempel kan det bruges til at spotte en bestemt metode i Testbar service:

@Test sjov givenServiceSpy_whenMockingOnlyOneMethod_thenOtherMethodsShouldBehaveAsOriginalObject () {// given val service = spyk () every {service.getDataFromDb (any ())} returnerer "Mocked Output" // når kontrol af spottet metode val firstResultrom = service.getata // derefter assertEquals ("Mocked Output", firstResult) // ved kontrol af ikke mocked metode val secondResult = service.doSomethingElse ("Enhver parameter") // derefter assertEquals ("Jeg vil ikke!", secondResult)}

I eksemplet har vi brugt spyk metode til at oprette et spionobjekt. Vi kunne også have brugt @SpyK kommentar for at opnå det samme:

klasse SpyKUnitTest {@SpyK lateinit var service: TestableService // Tests her}

7. Afslappet Mock

En typisk spottet genstand vil kaste MockKException hvis vi prøver at kalde en metode, hvor returværdien ikke er specificeret.

Hvis vi ikke ønsker at beskrive hver metodes opførsel, kan vi bruge en afslappet mock. Denne slags mock giver standardværdier for hver funktion. F.eks Snor retur type returnerer en tom Snor. Her er et kort eksempel:

@Test sjov givenRelaxedMock_whenCallingNotMockedMethod_thenReturnDefaultValue () {// given val service = mockk (relaxed = true) // when val result = service.getDataFromDb ("Any Param") // then assertEquals ("", result)}

I eksemplet har vi brugt mockk metode med afslappet attribut for at skabe et afslappet mock-objekt. Vi kunne også have brugt @RelaxedMockK kommentar:

klasse RelaxedMockKUnitTest {@RelaxedMockK lateinit var service: TestableService // Tests her}

8. Objekt Mock

Kotlin giver en nem måde at erklære en singleton ved hjælp af objekt nøgleord:

objekt TestableService {fun getDataFromDb (testParameter: String): String {// forespørgselsdatabase og returneringsmatchværdi}}

Imidlertid har de fleste af de spottende biblioteker et problem med at spotte Kotlin-singleton-forekomster. På grund af dette giver MockK den mockkObject metode. Lad os se:

@Test sjov givenObject_whenMockingIt_thenMockedMethodShouldReturnProperValue () {// given mockkObject (TestableService) // når der kaldes ikke mocked metode val firstResult = service.getDataFromDb ("Enhver Param") // returner derefter reelt svar assertEquals (/ * DB resultat * /, // når der kaldes en mocked metode, returnerer hver {service.getDataFromDb (any ())} "Mocked Output" val secondResult = service.getDataFromDb ("Any Param") // returnerer derefter mocked respons assertEquals ("Mocked Output", secondResult)}

9. Hierarkisk hån

Et andet nyttigt træk ved MockK er evnen til at spotte hierarkiske objekter. Lad os først oprette en hierarkisk objektstruktur:

klasse Foo {lateinit var navn: String lateinit var bar: Bar} class Bar {lateinit var kaldenavn: String}

Det Foo klasse indeholder et felt af typen Bar. Nu kan vi spotte strukturen i bare et let trin. Lad os spotte navn og kaldenavn felter:

@Test fun givenHierarchicalClass_whenMockingIt_thenReturnProperValue () {// given val foo = mockk {every {name} returnerer "Karol" hver {bar} returnerer mockk {hver {nickname} returnerer "Tomat"}} // når val name = foo.name val kaldenavn = foo.bar.nickname // derefter assertEquals ("Karol", navn) assertEquals ("Tomat", kaldenavn)}

10. Optagelse af parametre

Hvis vi har brug for at fange de parametre, der sendes til en metode, kan vi bruge dem CapturingSlot eller MutableList. Det er nyttigt, når vi vil have en brugerdefineret logik i en svar blokere, eller vi skal bare verificere værdien af ​​de argumenter, der er sendt. Her er et eksempel på CapturingSlot:

@Test fun givenMock_whenCapturingParamValue_thenProperValueShouldBeCaptured () {// given val service = mockk () val slot = slot () every {service.getDataFromDb (capture (slot))} returnerer "Expected Output" // når service.getDataFromDb ("Expected Param" ) // derefter assertEquals ("Forventet parameter", slot.captured)}

MutableList kan bruges til at indfange og gemme specifikke argumentværdier til alle metodeopkald:

@Test fun givenMock_whenCapturingParamsValues_thenProperValuesShouldBeCaptured () {// given val service = mockk () val list = mutableListOf () every {service.getDataFromDb (capture (list))} returnerer "Expected Output" // når service.getDataFromDb (" ") service.getDataFromDb (" Forventet Param 2 ") // derefter assertEquals (2, list.størrelse) assertEquals (" Forventet Param 1 ", liste [0]) assertEquals (" Forventet Param 2 ", liste [1])}

11. Konklusion

I denne artikel har vi diskuteret de vigtigste funktioner i MockK. MockK er et kraftfuldt bibliotek til Kotlin-sproget og indeholder mange nyttige funktioner. For mere information om MockK kan vi kontrollere dokumentationen på MockK-webstedet.

Som altid er den præsenterede prøvekode tilgængelig på GitHub.