Comprehensive mocking library for Kotlin with native coroutine support and advanced DSL features.
—
Annotation-based mock initialization system with automatic dependency injection and comprehensive JUnit integration for streamlined test setup and lifecycle management.
Annotations for automatic mock creation and initialization.
/**
* Creates a mock instance
* @property name Optional name for the mock
* @property relaxed If true, unstubbed methods return default values
* @property relaxUnitFun If true, only Unit-returning methods are relaxed
*/
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class MockK(
val name: String = "",
val relaxed: Boolean = false,
val relaxUnitFun: Boolean = false
)
/**
* Creates a relaxed mock instance (equivalent to @MockK(relaxed = true))
* @property name Optional name for the mock
*/
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class RelaxedMockK(
val name: String = ""
)
/**
* Creates a spy instance
* @property name Optional name for the spy
* @property recordPrivateCalls If true, enables private call recording
*/
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class SpyK(
val name: String = "",
val recordPrivateCalls: Boolean = true
)
/**
* Creates a capturing slot
*/
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class SlotUsage Examples:
class UserServiceTest {
@MockK
lateinit var userRepository: UserRepository
@RelaxedMockK
lateinit var logger: Logger
@SpyK
var emailService = EmailService()
@MockK(name = "testCache", relaxUnitFun = true)
lateinit var cache: CacheService
@Slot
lateinit var userSlot: CapturingSlot<User>
@BeforeEach
fun setUp() {
MockKAnnotations.init(this)
}
@Test
fun testUserCreation() {
// Mocks are automatically initialized
every { userRepository.save(capture(userSlot)) } returns User("123", "John")
val userService = UserService(userRepository, logger, emailService, cache)
userService.createUser("John", "john@example.com")
verify { userRepository.save(any()) }
assertEquals("John", userSlot.captured.name)
}
}Automatic injection of mocks into test subjects.
/**
* Injects mocks into the annotated property
* @property lookupType Strategy for finding mocks to inject
* @property injectImmutable If true, can inject into val properties
* @property overrideValues If true, overrides existing property values
*/
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
annotation class InjectMockKs(
val lookupType: InjectionLookupType = InjectionLookupType.BOTH,
val injectImmutable: Boolean = false,
val overrideValues: Boolean = false
)
enum class InjectionLookupType {
/** Inject by property name matching */
BY_NAME,
/** Inject by type matching */
BY_TYPE,
/** Try both name and type matching */
BOTH
}Usage Examples:
class UserService(
private val userRepository: UserRepository,
private val emailService: EmailService,
private val logger: Logger
) {
fun createUser(name: String, email: String): User {
val user = User(generateId(), name, email)
userRepository.save(user)
emailService.sendWelcomeEmail(user)
logger.info("User created: ${user.id}")
return user
}
}
class UserServiceTest {
@MockK
lateinit var userRepository: UserRepository
@MockK
lateinit var emailService: EmailService
@RelaxedMockK
lateinit var logger: Logger
@InjectMockKs
lateinit var userService: UserService
@BeforeEach
fun setUp() {
MockKAnnotations.init(this)
// userService now has mocks injected automatically
}
@Test
fun testUserCreation() {
every { userRepository.save(any()) } returns User("123", "John", "john@example.com")
val result = userService.createUser("John", "john@example.com")
verify { userRepository.save(any()) }
verify { emailService.sendWelcomeEmail(any()) }
assertEquals("123", result.id)
}
}Specify additional interfaces for mocks to implement.
/**
* Specifies additional interfaces for the mock to implement
* @property type Interface class to implement
*/
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
@Repeatable
annotation class AdditionalInterface(
val type: KClass<*>
)Usage Examples:
interface Auditable {
fun getAuditInfo(): String
}
interface Serializable
class ServiceTest {
@MockK
@AdditionalInterface(Auditable::class)
@AdditionalInterface(Serializable::class)
lateinit var userService: UserService
@BeforeEach
fun setUp() {
MockKAnnotations.init(this)
}
@Test
fun testAdditionalInterfaces() {
// Mock now implements UserService, Auditable, and Serializable
every { (userService as Auditable).getAuditInfo() } returns "audit-info"
val auditInfo = (userService as Auditable).getAuditInfo()
assertEquals("audit-info", auditInfo)
assertTrue(userService is Serializable)
}
}Functions for initializing annotated mocks.
object MockKAnnotations {
/**
* Initializes properties annotated with mock annotations
* @param obj Objects to initialize annotations for
* @param overrideRecordPrivateCalls Override recordPrivateCalls setting
* @param relaxUnitFun Global relaxUnitFun setting
* @param relaxed Global relaxed setting
*/
inline fun init(
vararg obj: Any,
overrideRecordPrivateCalls: Boolean = false,
relaxUnitFun: Boolean = false,
relaxed: Boolean = false
)
}Usage Examples:
class UserServiceTest {
@MockK
lateinit var userRepository: UserRepository
@RelaxedMockK
lateinit var logger: Logger
@SpyK
var emailService = EmailService()
@InjectMockKs
lateinit var userService: UserService
@BeforeEach
fun setUp() {
// Initialize all annotated properties
MockKAnnotations.init(this)
}
// Alternative: Initialize with global settings
@BeforeEach
fun setUpWithGlobalSettings() {
MockKAnnotations.init(
this,
overrideRecordPrivateCalls = true,
relaxUnitFun = true,
relaxed = false
)
}
// Initialize multiple test objects
@BeforeEach
fun setUpMultiple() {
val helperTest = TestHelper()
MockKAnnotations.init(this, helperTest)
}
}Automatic mock lifecycle management for JUnit 5 tests.
/**
* JUnit 5 extension for MockK integration
* Provides automatic mock initialization and cleanup
*/
class MockKExtension :
BeforeEachCallback,
AfterEachCallback,
ParameterResolverUsage Examples:
@ExtendWith(MockKExtension::class)
class UserServiceTest {
@MockK
lateinit var userRepository: UserRepository
@RelaxedMockK
lateinit var logger: Logger
@InjectMockKs
lateinit var userService: UserService
// Mocks are automatically initialized before each test
// and cleaned up after each test
@Test
fun testUserCreation() {
every { userRepository.save(any()) } returns User("123", "John")
val result = userService.createUser("John", "john@example.com")
verify { userRepository.save(any()) }
assertEquals("123", result.id)
}
// Parameter injection (JUnit 5 only)
@Test
fun testWithInjectedMock(@MockK emailService: EmailService) {
every { emailService.sendEmail(any(), any()) } returns true
val result = emailService.sendEmail("test@example.com", "Hello")
assertTrue(result)
}
}Annotations for configuring MockK behavior in JUnit 5 tests.
/**
* Prevents calling unmockkAll after each test
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class KeepMocks
/**
* Enables automatic confirmVerified calls after test execution
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class ConfirmVerification
/**
* Enables automatic checkUnnecessaryStub calls after test execution
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class CheckUnnecessaryStub
/**
* Disables clearAllMocks for thread safety in parallel testing
*/
@Target(AnnotationTarget.CLASS)
annotation class RequireParallelTestingUsage Examples:
@ExtendWith(MockKExtension::class)
@ConfirmVerification
@CheckUnnecessaryStub
class UserServiceTest {
@MockK
lateinit var userRepository: UserRepository
@InjectMockKs
lateinit var userService: UserService
@Test
fun testUserCreation() {
every { userRepository.save(any()) } returns User("123", "John")
userService.createUser("John", "john@example.com")
verify { userRepository.save(any()) }
// confirmVerified and checkUnnecessaryStub called automatically
}
@Test
@KeepMocks
fun testWithPersistentMocks() {
// Mocks are kept after this test
every { userRepository.findById("123") } returns User("123", "John")
}
}
@ExtendWith(MockKExtension::class)
@RequireParallelTesting
class ParallelTest {
// Safe for parallel execution
}MockK integration for JUnit 4 tests.
/**
* JUnit 4 rule for MockK integration
* @param obj Test object to initialize mocks for
* @param confirmVerification Enable automatic confirmVerified calls
* @param checkUnnecessaryStub Enable automatic checkUnnecessaryStub calls
*/
class MockKRule(
private val obj: Any,
private val confirmVerification: Boolean = false,
private val checkUnnecessaryStub: Boolean = false
) : TestRuleUsage Examples:
class UserServiceTest {
@MockK
lateinit var userRepository: UserRepository
@RelaxedMockK
lateinit var logger: Logger
@InjectMockKs
lateinit var userService: UserService
@get:Rule
val mockkRule = MockKRule(this)
// Alternative with verification checks
@get:Rule
val strictMockkRule = MockKRule(
this,
confirmVerification = true,
checkUnnecessaryStub = true
)
@Test
fun testUserCreation() {
every { userRepository.save(any()) } returns User("123", "John")
val result = userService.createUser("John", "john@example.com")
verify { userRepository.save(any()) }
assertEquals("123", result.id)
}
}Recommended patterns for using MockK annotations effectively.
// Recommended test structure
@ExtendWith(MockKExtension::class)
class UserServiceTest {
// Required dependencies as mocks
@MockK
lateinit var userRepository: UserRepository
@MockK
lateinit var emailService: EmailService
// Optional dependencies as relaxed mocks
@RelaxedMockK
lateinit var logger: Logger
@RelaxedMockK
lateinit var metrics: MetricsService
// Test subject with automatic injection
@InjectMockKs
lateinit var userService: UserService
// Capture slots for argument verification
@Slot
lateinit var userSlot: CapturingSlot<User>
@Slot
lateinit var emailSlot: CapturingSlot<String>
@Test
fun testCompleteUserFlow() {
// Setup
every { userRepository.save(capture(userSlot)) } returns User("123", "John")
every { emailService.sendWelcomeEmail(capture(emailSlot)) } returns true
// Execute
val result = userService.createUser("John", "john@example.com")
// Verify
verify { userRepository.save(any()) }
verify { emailService.sendWelcomeEmail("john@example.com") }
assertEquals("John", userSlot.captured.name)
assertEquals("john@example.com", emailSlot.captured)
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-mockk--mockk