MockK: Podrugljiva knjižnica za Kotlina

1. Pregled

U ovom uputstvu ćemo pogledati neke od osnovnih značajki MockK biblioteke.

2. MockK

U Kotlinu su svi razredi i metode konačni. Iako nam ovo pomaže u pisanju nepromjenjivog koda, također uzrokuje neke probleme tijekom testiranja.

Većina JVM lažnih knjižnica ima problema s izrugivanjem ili zapinjanjem završnih predavanja. Naravno, možemo dodati "otvorena”Ključna riječ za klase i metode kojima se želimo rugati. Ali mijenjati nastavu samo radi ismijavanja nekog koda ne čini se najboljim pristupom.

Evo biblioteke MockK koja nudi podršku za značajke i konstrukcije jezika Kotlin. MockK izrađuje proxyje za izrugivane klase. To uzrokuje određenu degradaciju performansi, ali ukupne prednosti koje nam MockK pruža vrijede.

3. Instalacija

Instalacija je što jednostavnija. Samo trebamo dodati mockk ovisnost našem projektu Maven:

 io.mockk mockk 1.9.3 test 

Za Gradle moramo ga dodati kao testnu ovisnost:

testImplementacija "io.mockk: mockk: 1.9.3"

4. Osnovni primjer

Stvorimo uslugu koju bismo željeli ismijavati:

klasa TestableService {zabava getDataFromDb (testParameter: String): Niz {// baza podataka upita i vrati podudarnu vrijednost} zabava doSomethingElse (testParameter: String): Niz {return "Ne želim!" }}

Evo primjera testa koji se ruga TestableService:

@Test zabava givenServiceMock_whenCallingMockedMethod_thenCorrectVerified () {// data val service = mockk () svaki {service.getDataFromDb ("Expected Param")} vraća "Očekivani izlaz" // kada val result = service.getDataFromDb ("Očekivani param") // zatim provjerite {service.getDataFromDb ("Očekivana parama")} assertEquals ("Očekivani izlaz", rezultat)}

Da bismo definirali lažni objekt, koristili smo podsmijeh () metoda.

U sljedećem smo koraku definirali ponašanje svog lažnog čovjeka. U tu svrhu stvorili smo svaki blok koji opisuje koji odgovor treba vratiti za koji poziv.

Konačno, koristili smo provjeriti blok da provjeri je li se lažno pozvalo kako smo očekivali.

5. Primjer bilješke

MockK napomene je moguće koristiti za stvaranje svih vrsta podsmijeha. Stvorimo uslugu koja zahtijeva dvije instance našeg TestableService:

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

InjectTestService sadrži dva polja istog tipa. MockK-u to neće predstavljati problem. MockK pokušava svojstva podudarati po imenu, a zatim po klasi ili superklasi. Također nema problema s ubrizgavanjem predmeta u privatna polja.

Rugajmo se InjectTestService u testu pomoću bilješki:

klasa AnnotationMockKUnitTest {@MockK lateinit var service1: TestableService @MockK lateinit var service2: TestableService @InjectMockKs var objectUnderTest = InjectTestService () @BeforeEach fun setUp () = MockKAnnotations.inits (TeckKAnnotations.inits (InTest)}

U gornjem primjeru koristili smo @InjectMockKs bilješka. Ovo specificira objekt u koji treba ubrizgati definirane podsmjehe. Prema zadanim postavkama ubrizgava varijable koje još nisu dodijeljene. Možemo koristiti @OverrideMockKs nadjačati polja koja već imaju vrijednost.

MockK zahtijeva MockKAnnotations.init (…) biti pozvan na objektu koji deklarira varijablu s napomenama. Za Junit5 se može zamijeniti sa @ExtendWith (MockKExtension :: class).

6. Špijun

Špijun omogućuje ruganje samo određenom dijelu neke klase. Na primjer, može se koristiti za ruganje određenoj metodi u TestableService:

@Test zabava givenServiceSpy_whenMockingOnlyOneMethod_thenOtherMethodsShouldBehaveAsOriginalObject () {// given val service = spyk () svaki {service.getDataFromDb (any ())} vraća "Mocked Output" // pri provjeri ismijane metode val firstDesulttaFaramDragetBehart // zatim assertEquals ("Ismijani izlaz", firstResult) // pri provjeri ne ismijane metode val secondResult = service.doSomethingElse ("Any Param") // tada assertEquals ("Ne želim!", secondResult)}

U primjeru smo koristili špijun metoda za stvaranje špijunskog objekta. Mogli smo i koristiti @SpyK napomena za postizanje istog:

klasa SpyKUnitTest {@SpyK lateinit var usluga: TestableService // Testovi ovdje}

7. Opušteno ruganje

Tipični ismijani predmet će baciti MockKException ako pokušamo pozvati metodu gdje povratna vrijednost nije navedena.

Ako ne želimo opisivati ​​ponašanje svake metode, tada možemo koristiti opušteno ismijavanje. Ova vrsta ismijavanja pruža zadane vrijednosti za svaku funkciju. Na primjer, Niz tip return vratit će prazno Niz. Evo kratkog primjera:

@Test zabava givenRelaxedMock_whenCallingNotMockedMethod_thenReturnDefaultValue () {// data val service = mockk (relaxed = true) // kada val result = service.getDataFromDb ("Any Param") // then assertEquals ("", result)}

U primjeru smo koristili rugalica metoda s opušten atribut za stvaranje opuštenog lažnog objekta. Mogli smo i koristiti @RelaxedMockK napomena:

klasa RelaxedMockKUnitTest {@RelaxedMockK lateinit var usluga: TestableService // Testovi ovdje}

8. Ruganje objektu

Kotlin pruža jednostavan način deklariranja singletona pomoću objekt ključna riječ:

objekt TestableService {fun getDataFromDb (testParameter: String): String {// baza podataka upita i vratiti podudarnu vrijednost}}

Međutim, većina ismijavajućih knjižnica ima problem s ismijavanjem instanci Kotlina singletona. Zbog toga MockK nudi mockkObject metoda. Pogledajmo:

@Test zabava givenObject_whenMockingIt_thenMockedMethodShouldReturnProperValue () {// zadani mockkObject (TestableService) // prilikom pozivanja ne rugajuće metode val firstResult = service.getDataFromDb ("Bilo koja parama") // zatim se vraća realan odgovor assertEquals (/ * prvi DB DBEQUALS (/ * DBR rezultat (/ * R)) // prilikom pozivanja ismijane metode svaki {service.getDataFromDb (bilo koji ())} vraća "Ismijani izlaz" val secondResult = service.getDataFromDb ("Bilo koja parama") // zatim vraća izruženi odgovor assertEquals ("Ismijani izlaz", secondResult)}

9. Hijerarhijsko ruganje

Još jedna korisna značajka MockK-a je sposobnost ismijavanja hijerarhijskih objekata. Prvo, kreirajmo hijerarhijsku strukturu objekta:

class Foo {lateinit var name: String lateinit var bar: Bar} class Bar {lateinit var nadimak: String}

The Foo klasa sadrži polje tipa Bar. Sada se strukturi možemo rugati u samo jednom laganom koraku. Rugajmo se Ime i nadimak polja:

@Test zabava givenHierarchicalClass_whenMockingIt_thenReturnProperValue () {// data val foo = mockk {svaki {name} vraća "Karol" svaki {bar} vraća mockk {svaki {nickname} vraća "Tomato"}} // kada je val name = foo.name val nadimak = foo.bar.nickname // zatim assertEquals ("Karol", ime) assertEquals ("Tomato", nadimak)}

10. Snimanje parametara

Ako trebamo uhvatiti parametre proslijeđene metodi, tada možemo koristiti CapturingSlot ili Promjenjiva lista. Korisno je kada želimo imati neku prilagođenu logiku u odgovor blok ili samo trebamo provjeriti vrijednost prosljeđenih argumenata. Evo primjera CapturingSlot:

@Test zabava givenMock_whenCapturingParamValue_thenProperValueShouldBeCaptured () {// data val service = mockk () val slot = slot () svaki {service.getDataFromDb (capture (slot))}} vraća "Očekivani izlaz" // kada service.getDataFromDb " ) // zatim assertEquals ("Očekivana parama", slot.captured)}

Promjenjiva lista može se koristiti za hvatanje i spremanje određenih vrijednosti argumenata za sve pozive metode:

@Test zabava givenMock_whenCapturingParamsValues_thenProperValuesShouldBeCaptured () {// data val service = mockk () val list = mutableListOf () svaki {service.getDataFromDb (capture (list))} vraća "Očekivani izlaz" // kada service.getDataFrom ") service.getDataFromDb (" Očekivani param 2 ") // zatim assertEquals (2, list.size) assertEquals (" Očekivani param 1 ", popis [0]) assertEquals (" Očekivani param 2 ", popis [1])}

11. Zaključak

U ovom smo članku razgovarali o najvažnijim značajkama MockK-a. MockK je moćna knjižnica za jezik Kotlin i nudi puno korisnih značajki. Za više informacija o MockK-u možemo provjeriti dokumentaciju na web mjestu MockK.

Kao i uvijek, predstavljeni uzorak koda dostupan je na GitHub-u.