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

matchers.mddocs/

Matchers

Sophisticated argument matching system with built-in matchers for equality, comparison, type checking, capturing, and logical operations to create flexible and powerful mock interactions.

Capabilities

Basic Matchers

Fundamental argument matching functions for common scenarios.

/**
 * Matches any argument of the specified type
 */
fun <T> any(): T

/**
 * Matches any nullable argument
 */
fun <T> anyNullable(): T?

/**
 * Matches arguments equal to the specified value
 * @param value Value to match against
 * @param inverse If true, matches non-equal values
 */
fun <T> eq(value: T, inverse: Boolean = false): T

/**
 * Matches arguments not equal to the specified value
 * @param value Value to not match
 */
fun <T> neq(value: T): T

Usage Examples:

val userService = mockk<UserService>()

// Match any argument
every { userService.getUserById(any()) } returns User("default", "Default User")

// Match specific value
every { userService.getUserById(eq("123")) } returns User("123", "John")

// Match not equal to value
every { userService.getUserById(neq("admin")) } returns User("user", "Regular User")

// Use in verification
verify { userService.saveUser(any()) }
verify { userService.getUserById(eq("123")) }

Reference Equality Matchers

Matchers based on reference equality rather than value equality.

/**
 * Matches arguments with same reference as the specified value
 * @param value Reference to match against
 * @param inverse If true, matches different references
 */
fun <T> refEq(value: T, inverse: Boolean = false): T

/**
 * Matches arguments with different reference than the specified value
 * @param value Reference to not match
 */
fun <T> nrefEq(value: T): T

Usage Examples:

val userService = mockk<UserService>()
val specificUser = User("123", "John")

// Match same reference
every { userService.processUser(refEq(specificUser)) } returns "processed"

// Match different reference
every { userService.processUser(nrefEq(specificUser)) } returns "different object"

// Verification with reference equality
verify { userService.processUser(refEq(specificUser)) }

Comparison Matchers

Matchers for numerical and comparable value comparisons.

/**
 * Matches arguments greater than the specified value
 * @param value Comparison value
 * @param andEquals If true, includes equal values (>=)
 */
fun <T : Comparable<T>> more(value: T, andEquals: Boolean = false): T

/**
 * Matches arguments less than the specified value
 * @param value Comparison value
 * @param andEquals If true, includes equal values (<=)
 */
fun <T : Comparable<T>> less(value: T, andEquals: Boolean = false): T

/**
 * Matches arguments within the specified range
 * @param from Range start value
 * @param to Range end value
 * @param fromInclusive Include start value (default: true)
 * @param toInclusive Include end value (default: true)
 */
fun <T : Comparable<T>> range(
    from: T, 
    to: T, 
    fromInclusive: Boolean = true, 
    toInclusive: Boolean = true
): T

/**
 * Matches using Comparable.compareTo for equality
 * @param value Value to compare against
 */
fun <T : Comparable<T>> cmpEq(value: T): T

Usage Examples:

val userService = mockk<UserService>()

// Numerical comparisons
every { userService.getUsersWithAge(more(18)) } returns listOf(/* adults */)
every { userService.getUsersWithAge(less(65, andEquals = true)) } returns listOf(/* non-seniors */)
every { userService.getUsersWithAge(range(18, 65)) } returns listOf(/* working age */)

// String comparisons
every { userService.getUsersWithNameAfter(more("M")) } returns listOf(/* names N-Z */)

// Verification with comparisons
verify { userService.processUsersWithScore(more(80)) }

Type Checking Matchers

Matchers for type-based argument matching.

/**
 * Matches arguments of the specified type
 */
inline fun <reified T> ofType(): T

/**
 * Matches null values
 * @param inverse If true, matches non-null values
 */
fun <T> isNull(inverse: Boolean = false): T?

Usage Examples:

val userService = mockk<UserService>()

// Match by type
every { userService.processEntity(ofType<User>()) } returns "user processed"
every { userService.processEntity(ofType<Admin>()) } returns "admin processed"

// Match null/non-null
every { userService.processOptionalData(isNull()) } returns "no data"
every { userService.processOptionalData(isNull(inverse = true)) } returns "has data"

// Verification with type matching
verify { userService.processEntity(ofType<User>()) }

Logical Combinators

Matchers for combining multiple matching conditions.

/**
 * Matches arguments that satisfy both matchers (logical AND)
 * @param left First matcher
 * @param right Second matcher
 */
fun <T> and(left: T, right: T): T

/**
 * Matches arguments that satisfy either matcher (logical OR)
 * @param left First matcher
 * @param right Second matcher
 */
fun <T> or(left: T, right: T): T

/**
 * Matches arguments that do NOT satisfy the matcher (logical NOT)
 * @param value Matcher to negate
 */
fun <T> not(value: T): T

Usage Examples:

val userService = mockk<UserService>()

// Logical AND - age between 18-65 AND name starts with "J"
every { 
    userService.processUser(and(
        match { it.age in 18..65 },
        match { it.name.startsWith("J") }
    ))
} returns "processed special user"

// Logical OR - either admin or premium user
every {
    userService.processUser(or(
        match { it.type == UserType.ADMIN },
        match { it.isPremium }
    ))
} returns "processed privileged user"

// Logical NOT - not a test user
every { userService.processUser(not(match { it.isTestUser })) } returns "processed real user"

Capturing Matchers

Matchers that capture arguments for later inspection.

/**
 * Captures argument to a list
 * @param lst Mutable list to capture values into
 */
fun <T> capture(lst: MutableList<T>): T

/**
 * Captures argument to a capturing slot
 * @param slot CapturingSlot to capture value into
 */
fun <T> capture(slot: CapturingSlot<T>): T

/**
 * Captures nullable argument to a list
 * @param lst Mutable list to capture values into
 */
fun <T> captureNullable(lst: MutableList<T?>): T?

/**
 * Captures nullable argument to a capturing slot
 * @param slot CapturingSlot to capture value into
 */
fun <T> captureNullable(slot: CapturingSlot<T?>): T?

Usage Examples:

val userService = mockk<UserService>()
val capturedUsers = mutableListOf<User>()
val userSlot = slot<User>()

// Capture to list
every { userService.saveUser(capture(capturedUsers)) } returns "saved"

// Capture to slot
every { userService.updateUser(capture(userSlot)) } returns "updated"

// Make calls
userService.saveUser(User("1", "John"))
userService.saveUser(User("2", "Jane"))
userService.updateUser(User("3", "Bob"))

// Access captured values
val allSavedUsers = capturedUsers // [User("1", "John"), User("2", "Jane")]
val lastUpdatedUser = userSlot.captured // User("3", "Bob")

Custom Matchers

Create custom matching logic using the match function.

/**
 * Matches arguments using custom matcher logic
 * @param matcher Custom Matcher implementation
 */
fun <T> match(matcher: Matcher<T>): T

/**
 * Matches arguments using lambda-based matching
 * @param predicate Lambda that returns true for matching arguments
 */
inline fun <reified T> match(noinline predicate: (T?) -> Boolean): T

interface Matcher<in T> {
    fun match(arg: T?): Boolean
    fun substitute(map: Map<Any, Any>): Matcher<T>
}

Usage Examples:

val userService = mockk<UserService>()

// Lambda-based matching
every { 
    userService.processUser(match { user ->
        user != null && user.name.length > 5 && user.age > 18
    })
} returns "processed valid user"

// Custom Matcher implementation
class EmailMatcher : Matcher<String> {
    override fun match(arg: String?): Boolean {
        return arg?.contains("@") == true
    }
    
    override fun substitute(map: Map<Any, Any>): Matcher<String> = this
}

every { userService.sendEmail(match(EmailMatcher())) } returns "email sent"

// Verification with custom matching
verify { 
    userService.processUser(match { it?.name?.startsWith("J") == true })
}

Array and Collection Matchers

Specialized matchers for arrays and collections.

/**
 * Matches any vararg arguments
 */
fun <T> anyVararg(): Array<T>

/**
 * Matches varargs where all elements satisfy the condition
 * @param matcher Matcher that all elements must satisfy
 */
fun <T> varargAll(matcher: T): Array<T>

/**
 * Matches varargs where any element satisfies the condition
 * @param matcher Matcher that at least one element must satisfy
 */
fun <T> varargAny(matcher: T): Array<T>

// Primitive array matchers
fun anyIntVararg(): IntArray
fun anyBooleanVararg(): BooleanArray
fun anyByteVararg(): ByteArray
fun anyCharVararg(): CharArray
fun anyShortVararg(): ShortArray
fun anyLongVararg(): LongArray
fun anyFloatVararg(): FloatArray
fun anyDoubleVararg(): DoubleArray

Usage Examples:

interface LogService {
    fun log(level: String, vararg messages: String)
    fun logNumbers(vararg numbers: Int)
}

val logService = mockk<LogService>()

// Match any varargs
every { logService.log("INFO", *anyVararg()) } just Runs

// Match varargs with conditions
every { 
    logService.log("ERROR", *varargAll(match { it.contains("error") }))
} just Runs

// Match primitive varargs
every { logService.logNumbers(*anyIntVararg()) } just Runs

// Verification with varargs
verify { logService.log("INFO", *anyVararg()) }

Function and Lambda Matchers

Matchers for function types and lambda arguments.

/**
 * Captures lambda functions for execution
 */
fun <T> captureLambda(): T

/**
 * Captures coroutine functions
 */
fun <T> captureCoroutine(): T

/**
 * Matches function invocations (up to 22 parameters)
 */
fun invoke(): Function0<*>
fun <T1> invoke(arg1: T1): Function1<T1, *>
fun <T1, T2> invoke(arg1: T1, arg2: T2): Function2<T1, T2, *>
// ... up to Function22

/**
 * Matches coroutine function invocations
 */
fun coInvoke(): suspend () -> Any?
fun <T1> coInvoke(arg1: T1): suspend (T1) -> Any?
// ... and so on

Usage Examples:

interface CallbackService {
    fun processWithCallback(data: String, callback: (String) -> Unit)
    fun processAsync(data: String, callback: suspend (String) -> Unit)
}

val callbackService = mockk<CallbackService>()
val lambdaSlot = slot<(String) -> Unit>()

// Capture lambda for later execution
every { 
    callbackService.processWithCallback(any(), captureLambda())
} answers {
    val callback = secondArg<(String) -> Unit>()
    callback("processed: ${firstArg<String>()}")
}

// Match function invocation
every { 
    callbackService.processWithCallback("test", invoke("result"))
} just Runs

// Verification with function matching
verify { 
    callbackService.processWithCallback("test", invoke("result"))
}

Universal Matchers

Matchers that handle special cases and universal matching.

/**
 * Matches any argument (most permissive matcher)
 */
fun <T> allAny(): T

Usage Examples:

val userService = mockk<UserService>()

// Most permissive matching
every { userService.complexMethod(allAny(), allAny(), allAny()) } returns "result"

// Useful when exact matching is difficult
verify { userService.complexMethod(allAny(), allAny(), allAny()) }

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