CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-mockk--mockk

Comprehensive mocking library for Kotlin with native coroutine support and advanced DSL features.

Pending
Overview
Eval results
Files

annotations.mddocs/

Annotations

Annotation-based mock initialization system with automatic dependency injection and comprehensive JUnit integration for streamlined test setup and lifecycle management.

Capabilities

Core Mock Annotations

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 Slot

Usage 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)
    }
}

Dependency Injection

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)
    }
}

Additional Interface Annotation

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)
    }
}

Mock Initialization

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)
    }
}

JUnit Integration

JUnit 5 Extension

Automatic mock lifecycle management for JUnit 5 tests.

/**
 * JUnit 5 extension for MockK integration
 * Provides automatic mock initialization and cleanup
 */
class MockKExtension : 
    BeforeEachCallback, 
    AfterEachCallback, 
    ParameterResolver

Usage 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)
    }
}

JUnit 5 Configuration Annotations

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 RequireParallelTesting

Usage 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
}

JUnit 4 Rule

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
) : TestRule

Usage 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)
    }
}

Best Practices

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

docs

annotations.md

index.md

matchers.md

mock-creation.md

special-mocking.md

stubbing.md

verification.md

tile.json