MockK: ce este, concepte cheie și sintaxă

Autor: IT Sectr Publicat: 2026-04-08 Timp de citire: 8 min

MockK — este un cadru Kotlin-first pentru crearea obiectelor mock, proiectat special pentru ecosistemul Kotlin, ținând cont de caracteristicile sale lingvistice: corutine, funcții de extensie, data class și sealed class. Spre deosebire de Mockito, care a fost portat pe Kotlin din Java, MockK a fost conceput de la început pentru sintaxa Kotlin și nu necesită pluginuri suplimentare pentru a lucra cu clasele final. Conform datelor MockK.io, biblioteca este utilizată în peste 40% din proiectele Kotlin cu testare unitară.

Principalele

  • MockK — o bibliotecă orientată pe Kotlin pentru mockuri, cu suport pentru corutine și caracteristici ale limbajului.
  • mockk() — metoda principală de creare a unui obiect mock, similară cu Mockito.mock().
  • every { } — bloc pentru configurarea comportamentului mockului (stubbing) în stil declarativ.
  • coEvery / coVerify — construcții speciale pentru lucrul cu funcțiile suspend ale corutinelor.
  • Relaxed mock — un mock care returnează valori implicite fără stubbing explicit.

Ce este MockK?

MockK — este o bibliotecă pentru crearea obiectelor mock, scrisă în Kotlin și optimizată pentru sintaxa sa. Rezolvă aceleași sarcini ca Mockito — izolarea codului testat de dependențe — dar o face folosind construcții specifice Kotlin: lambda, DSL, reified generics și funcții suspend.

Principalul avantaj al MockK față de soluțiile portate — suportul nativ pentru Kotlin. În Mockito, mockarea clasei final necesită opt-in (mockito-inline), iar a metodelor statice — mockStatic. MockK suportă acest lucru implicit, deoarece clasele Kotlin sunt implicit final, iar ocolirea acestei limitări este încorporată în arhitectura bibliotecii.

Versiunea 1.13.12 (2024) — o versiune stabilă care suportă Kotlin 2.0, compilatorul K2 și proiecte multi-platformă (KMP). MockK funcționează și cu Kotlin/Native și Kotlin/JS, ceea ce îl face singura alegere pentru proiectele KMP unde nici Mockito, nici EasyMock nu sunt aplicabile.

MockK este proiectat ținând cont de specificul Kotlin și utilizează capacitățile limbajului — reified generics, DSL cu lambda, funcții inline — pentru a oferi o API concisă și sigură din punct de vedere al tipurilor, fără pierdere de performanță.

Cum funcționează MockK

Mecanismul MockK se bazează pe instrumentarea bytecodului prin biblioteca ByteBuddy (ca și Mockito), dar o îmbracă într-un DSL prietenos cu Kotlin. În locul lanțurilor when().thenReturn(), MockK folosește blocuri lambda every { } și coEvery { }, care arată ca o extensie naturală a limbajului. În culise, MockK interceptează apelul din interiorul lambdei, analizează metoda și argumentele prin reflexie și le potrivește cu regulile de stubbing înregistrate.

Sintaxa de bază MockK

Blocul every { mock.method() } returns value se citește ca „de fiecare dată când metoda este apelată, returnează valoarea”. O astfel de sintaxă declarativă este mai apropiată de stilul Kotlin și elimină confuzia cu ordinea argumentelor în when(). Datorită reified generics din Kotlin, tipul mockului este dedus automat fără specificarea explicită a clasei.

kotlin
val repository = mockk<UserRepository>()

// Stubbing: fiecare apel findById(1) returnează utilizatorul
every { repository.findById(1) } returns User("Alice")

// Apel și verificare
val result = repository.findById(1)
assertEquals("Alice", result.name)

Relaxed mock: mai puțin boilerplate

Spre deosebire de Mockito, unde fiecare metodă trebuie configurată explicit, MockK suportă relaxed mock — un mock care returnează valori implicite „rezonabile” pentru orice metodă: listă goală pentru List, 0 pentru Int, șir gol pentru String. Acest lucru reduce drastic cantitatea de cod pregătitor.

kotlin
// Relaxed mock — toate metodele returnează valori implicite
val api = mockk<ApiService>(relaxed = true)

// Nu necesită stubbing — va returna o listă goală
println(api.getUsers()) // []

Crearea mockurilor și a mockurilor relaxate

MockK oferă mai multe moduri de a crea obiecte mock: mockk<T>() pentru un mock strict (fiecare metodă trebuie configurată explicit), mockk<T>(relaxed = true) pentru un mock relaxat și spyk(obj) pentru a crea un spy pe un obiect real.

FuncțieTipComportament fără stubbing
mockk()Mock strictAruncă excepție la apelul unei metode nestubuite
mockk(relaxed = true)Mock relaxatReturnează valoarea implicită
spyk()SpyApelează metoda reală dacă nu este configurat un stub
slot()Argument CaptorCapturează argumentul pentru verificare

Alegerea între un mock strict și unul relaxat depinde de context. Mockul strict garantează că testul nu folosește metode al căror comportament nu este definit — acest lucru crește fiabilitatea. Mockul relaxat este convenabil pentru prototiparea rapidă a testelor unde nu toate dependențele sunt importante. În practică, se recomandă să începi cu un mock strict și să treci la relaxed doar când stubbingul ocupă mai multe linii decât testul însuși.

Stubbing: configurarea comportamentului cu blocul every

Blocul every — este construcția centrală a stubbingului în MockK. În interiorul lambdei se descrie un apel de metodă cu argumente specifice, iar apoi se returnează valoarea prin returns, se aruncă excepția prin throws sau se calculează răspunsul prin answers.

Diferite moduri de stubbing

MockK suportă toate scenariile necesare pentru testare: returnarea valorii, aruncarea excepției, calcularea răspunsului pe baza argumentelor, mai multe răspunsuri în ordine (secvența apelurilor).

kotlin
// Returnarea valorii
every { repo.findById(1) } returns User("Alice")

// Aruncarea excepției
every { repo.findById(999) } throws NotFoundException()

// Răspuns dinamic
every { repo.save(any()) } answers {
    val user = firstArg<User>()
    user.copy(id = 42)
}

// Secvența răspunsurilor
every { repo.findAll() } returnsMany listOf(
    listOf(User("Alice")),
    listOf(User("Bob")),
    emptyList()
)

Verify și coVerify pentru corutine

Verify în MockK este analog cu Mockito.verify() ca sens, dar folosește DSL-ul Kotlin: verify { mock.method() }. Pentru funcțiile suspend se folosește coVerify { mock.suspendMethod() }, care funcționează corect cu corutinele și nu necesită un runner special.

Verificarea numărului de apeluri

MockK suportă aceiași modificatori ca Mockito: exactly(1), atLeast(2), atMost(5), wasNot(Called). Sintaxa este minimalistă — modificatorul este transmis ca prim argument în verify { }.

kotlin
// Verificare: metoda apelată exact 1 dată
verify(exactly = 1) { repo.save(any()) }

// Verificarea ordinii apelurilor
verifySequence {
    repo.save(any())
    repo.flush()
}

// coVerify pentru funcții suspend
coVerify { api.fetchUsers() }

Slot: capturarea argumentelor

Pentru verificarea argumentelor se folosește slot() — analogul ArgumentCaptor. Slotul se declară înainte de apel, se transmite în every sau verify, iar după executarea testului conține valoarea capturată.

kotlin
val userSlot = slot<User>()

verify { repo.save(capture(userSlot)) }

assertEquals("Alice", userSlot.captured.name)

Adnotări MockK și integrare JUnit

MockK oferă adnotările @MockK și @RelaxedMockK pentru crearea mockurilor prin inițializare în JUnit 5. Extensia MockKExtension creează automat mockuri înainte de fiecare test și le curăță după — similar cu MockitoExtension, dar cu suport pentru modul relaxed.

Exemplu cu MockKExtension

Adnotarea @InjectMockKs (sau alternativa @MockK cu crearea explicită a obiectului) injectează mockurile în instanța testată. Acest lucru reduce boilerplate-ul și face codul testului mai curat.

kotlin
@ExtendWith(MockKExtension::class)
class UserServiceTest {

    @MockK
    lateinit var repository: UserRepository

    @InjectMockKs
    lateinit var service: UserService

    @Test
    fun `getUser returns user from repository`() {
        every { repository.findById(1) } returns User("Alice")
        assertEquals("Alice", service.getUser(1)?.name)
    }
}

MockK vs Mockito: ce să alegi pentru Kotlin

Alegerea între MockK și Mockito depinde de componența echipei și tipul proiectului. Mockito are un ecosistem mai mare, mai multe exemple și integrări, dar MockK oferă o sintaxă Kotlin mai curată și suport nativ pentru caracteristicile limbajului. Pentru proiectele noi Kotlin, MockK este recomandat ca soluție mai idiomatică.

CriteriuMockKMockito
SintaxăDSL Kotlin (every, verify)Stil Java (when, thenReturn)
CorutinecoEvery, coVerify (nativ)Necesită biblioteci suplimentare
Final classSuportat implicitNecesită mockito-inline
KMPSuportatNu este suportat
Relaxed mockÎncorporatNu are analog
PopularitateÎn creștere în comunitatea KotlinDomină în Java și proiecte hibride

Pentru proiectele în Kotlin pur (fără clase Java), MockK este preferat: mai puțin boilerplate, suport nativ pentru corutine, fără surprize cu clasele final. Pentru proiecte hibride sau echipe cu experiență Java, Mockito rămâne o opțiune funcțională — ambele biblioteci pot fi folosite în același proiect prin module diferite. La migrarea de la Mockito la MockK, este suficient să înlocuiești adnotările @Mock cu @MockK și să rescrii blocurile when().thenReturn() în formatul every { }.

Întrebări frecvente

Cu ce diferă relaxed mock de un mock obișnuit în MockK?

Relaxed mock returnează valori implicite pentru toate metodele nestubuite (listă goală, 0, null), fără a arunca excepții. Un mock obișnuit (strict) necesită stubbing explicit al fiecărei metode — altfel testul eșuează. Relaxed mock este convenabil pentru teste rapide, strict — pentru teste fiabile.

Cum se mockuiesc funcțiile de extensie în MockK?

MockK suportă mockuirea funcțiilor de extensie prin mockkStatic(). Acest lucru este posibil deoarece funcțiile de extensie în Kotlin sunt metode statice cu primul parametru receptor. Pentru fiecare funcție de extensie, trebuie specificată clasa în care este declarată.

Funcționează MockK cu Kotlin Multiplatform?

Da, MockK suportă Kotlin Multiplatform (KMP) pentru codul comun. Pe platformele JVM, Native și JS se poate folosi API-ul comun mockk(), every, verify. Acest lucru face din MockK singura alegere pentru proiectele KMP unde Mockito nu funcționează.

Cum se verifică ordinea apelurilor în MockK?

Folosește verifySequence { } — un bloc în care apelurile sunt specificate strict în ordinea așteptată. Dacă ordinea reală diferă, verifySequence va arunca o excepție cu indicarea primului apel nepotrivit.

Se pot folosi MockK și Mockito în același proiect?

Da, tehnic este posibil, dar nu este recomandat. Conflictele pot apărea la nivel de instrumentare a bytecodului (ByteBuddy vs mockito-inline). Dacă proiectul folosește deja Mockito, migrarea la MockK poate fi graduală prin izolarea modulelor.

Rezumat

  • MockK — o bibliotecă Kotlin-first pentru mockuri cu suport nativ al limbajului.
  • every { } — DSL declarativ pentru configurarea comportamentului mockurilor.
  • coEvery / coVerify — suport pentru funcțiile suspend ale corutinelor fără dependențe suplimentare.
  • Relaxed mock — un mock cu valori implicite care reduce boilerplate-ul.
  • @MockK / @InjectMockKs — adnotări pentru crearea automată a mockurilor în JUnit 5.
  • MockK vs Mockito — MockK este preferat pentru proiectele Kotlin pure și KMP.
  • verifySequence — verificarea ordinii stricte a apelurilor de metode.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și