MockK: Et hånlig bibliotek for Kotlin

1. Oversikt

I denne opplæringen skal vi ta en titt på noen av de grunnleggende funksjonene i MockK-biblioteket.

2. MockK

I Kotlin er alle klasser og metoder endelige. Selv om dette hjelper oss med å skrive uforanderlig kode, forårsaker det også noen problemer under testing.

De fleste JVM-mock-biblioteker har problemer med å spotte eller stubbe finalekursene. Selvfølgelig kan vi legge til "åpen”Nøkkelord til klasser og metoder som vi ønsker å spotte. Men å endre klasser bare for å spotte litt kode, føles ikke som den beste tilnærmingen.

Her kommer MockK-biblioteket, som tilbyr støtte for Kotlin-språkfunksjoner og -konstruksjoner. MockK bygger fullmakter for spottede klasser. Dette fører til en viss ytelsesforringelse, men de samlede fordelene som MockK gir oss er verdt det.

3. Installasjon

Installasjonen er så enkel som den kan være. Vi trenger bare å legge til mockk-avhengigheten til Maven-prosjektet vårt:

 io.mockk mockk 1.9.3 test 

For Gradle må vi legge det til som en testavhengighet:

testImplementation "io.mockk: mockk: 1.9.3"

4. Grunnleggende eksempel

La oss lage en tjeneste som vi vil spotte:

class TestableService {fun getDataFromDb (testParameter: String): String {// query database and return matching value} fun doSomethingElse (testParameter: String): String {return "Jeg vil ikke!" }}

Her er et eksempel på en test som håner Testbar tjeneste:

@Test fun givenServiceMock_whenCallingMockedMethod_thenCorrectlyVerified () {// given val service = mockk () every {service.getDataFromDb ("Expected Param")} returnerer "Expected Output" // when val result = service.getDataFromDb ("Expected Param") // bekreft deretter {service.getDataFromDb ("Expected Param")} assertEquals ("Expected Output", result)}

For å definere det spotte objektet har vi brukt mockk () metode.

I neste trinn definerte vi oppførselen til spottet vårt. For dette formålet har vi opprettet en hver blokk som beskriver hvilket svar som skal returneres for hvilken samtale.

Til slutt brukte vi bekrefte blokkere for å verifisere om mock ble påkalt som vi forventet.

5. Kommentareksempel

Det er mulig å bruke MockK-merknader for å lage alle slags mocks. La oss lage en tjeneste som krever to forekomster av vår Testbar tjeneste:

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

InjectTestService inneholder to felt med samme type. Det vil ikke være et problem for MockK. MockK prøver å matche egenskaper etter navn, deretter etter klasse eller superklasse. Det også har ikke noe problem med å injisere gjenstander i private felt.

La oss spotte InjectTestService i en test ved å bruke merknader:

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 eksemplet ovenfor har vi brukt @InjectMockKs kommentar. Dette spesifiserer et objekt der definerte mocks skal injiseres. Som standard injiserer den variabler som ikke er tildelt ennå. Vi kan bruke @OverrideMockKs for å overstyre felt som allerede har en verdi.

MockK krever MockKAnnotations.init (…) å bli kalt på et objekt som erklærer en variabel med merknader. For Junit5 kan den erstattes med @ExtendWith (MockKExtension :: klasse).

6. Spionere

Spy tillater bare å spotte en bestemt del av en klasse. For eksempel kan den brukes til å spotte en bestemt metode i Testbar tjeneste:

@Test fun givenServiceSpy_whenMockingOnlyOneMethod_thenOtherMethodsShouldBehaveAsOriginalObject () {// given val service = spyk () every {service.getDataFromDb (any ())} returnerer "Mocked Output" // når du sjekker spottet metode val firstResultrom = service.getata // deretter assertEquals ("Mocked Output", firstResult) // når du sjekker ikke spottet metode val secondResult = service.doSomethingElse ("Any Param") // deretter assertEquals ("Jeg vil ikke!", secondResult)}

I eksemplet har vi brukt spyk metode for å lage et spionobjekt. Vi kunne også ha brukt @SpyK kommentar for å oppnå det samme:

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

7. Avslappet Mock

En typisk spottet gjenstand vil kaste MockKException hvis vi prøver å kalle en metode der returverdien ikke er spesifisert.

Hvis vi ikke vil beskrive oppførselen til hver metode, kan vi bruke en avslappet mock. Denne typen mock gir standardverdier for hver funksjon. For eksempel String retur type vil returnere en tom String. Her er et kort eksempel:

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

I eksemplet har vi brukt mockk metoden med avslappet attributt for å skape et avslappet mock-objekt. Vi kunne også ha brukt @RelaxedMockK kommentar:

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

8. Objekt Mock

Kotlin gir en enkel måte å erklære en singleton på gjenstand nøkkelord:

objekt TestableService {fun getDataFromDb (testParameter: String): String {// spørringsdatabase og retur samsvarende verdi}}

Imidlertid har de fleste av de hånende bibliotekene et problem med å spotte Kotlin-enkeltforekomster. På grunn av dette gir MockK den mockkObject metode. La oss ta en titt:

@Test fun givenObject_whenMockingIt_thenMockedMethodShouldReturnProperValue () {// given mockkObject (TestableService) // when calling not mocked method val firstResult = service.getDataFromDb ("Any Param") // then return real response assertEquals (/ * DB result * /, // når du ringer til spottet metode, returnerer hver {service.getDataFromDb (any ())} "Mocked Output" val secondResult = service.getDataFromDb ("Any Param") // returnerer deretter spottet respons assertEquals ("Mocked Output", secondResult)}

9. Hierarkisk hån

En annen nyttig funksjon i MockK er muligheten til å spotte hierarkiske objekter. La oss først lage en hierarkisk objektstruktur:

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

De Foo klasse inneholder et felt av typen Bar. Nå kan vi spotte strukturen i bare ett enkelt trinn. La oss spotte Navn og kallenavn Enger:

@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 kallenavn = foo.bar.nickname // deretter assertEquals ("Karol", navn) assertEquals ("Tomat", kallenavn)}

10. Fange parametere

Hvis vi trenger å fange opp parametrene som sendes til en metode, kan vi bruke dem CapturingSlot eller MutableList. Det er nyttig når vi ønsker å ha litt tilpasset logikk i en svar blokkere, eller vi trenger bare å verifisere verdien av argumentene som 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" // when service.getDataFromDb ("Expected Param" ) // deretter assertEquals ("Expected Param", slot.captured)}

MutableList kan brukes til å fange opp og lagre spesifikke argumentverdier for alle metodeanropninger:

@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 ") // deretter assertEquals (2, list.size) assertEquals (" Forventet Param 1 ", liste [0]) assertEquals (" Forventet Param 2 ", liste [1])}

11. Konklusjon

I denne artikkelen har vi diskutert de viktigste funksjonene i MockK. MockK er et kraftig bibliotek for Kotlin-språket og gir mange nyttige funksjoner. For mer informasjon om MockK, kan vi sjekke dokumentasjonen på MockK-nettstedet.

Som alltid er eksempelkoden som presenteres tilgjengelig på GitHub.


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