Helper functions to work with Mockito in Kotlin
—
Type-safe argument capturing with Kotlin-friendly APIs and support for multiple argument capture patterns. Essential for capturing and inspecting arguments passed to mock methods.
Functions for creating argument captors for different numbers of types.
/**
* Creates a KArgumentCaptor for the specified reified type
* @returns KArgumentCaptor instance for capturing arguments of type T
*/
inline fun <reified T : Any> argumentCaptor(): KArgumentCaptor<T>
/**
* Creates 2 KArgumentCaptors for given types
* @param a KClass for first type (defaults to reified A::class)
* @param b KClass for second type (defaults to reified B::class)
* @returns Pair of KArgumentCaptors for types A and B
*/
inline fun <reified A : Any, reified B : Any> argumentCaptor(
a: KClass<A> = A::class,
b: KClass<B> = B::class
): Pair<KArgumentCaptor<A>, KArgumentCaptor<B>>
/**
* Creates 3 KArgumentCaptors for given types
* @param a KClass for first type (defaults to reified A::class)
* @param b KClass for second type (defaults to reified B::class)
* @param c KClass for third type (defaults to reified C::class)
* @returns Triple of KArgumentCaptors for types A, B, and C
*/
inline fun <reified A : Any, reified B : Any, reified C : Any> argumentCaptor(
a: KClass<A> = A::class,
b: KClass<B> = B::class,
c: KClass<C> = C::class
): Triple<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>>Usage Examples:
import com.nhaarman.mockitokotlin2.*
// Single argument captor
val userCaptor = argumentCaptor<User>()
verify(userService).saveUser(userCaptor.capture())
val capturedUser = userCaptor.firstValue
// Multiple argument captors
val (userCaptor, emailCaptor) = argumentCaptor<User, String>()
verify(emailService).sendEmail(userCaptor.capture(), emailCaptor.capture())
val capturedUser = userCaptor.firstValue
val capturedEmail = emailCaptor.firstValue
// Three argument captors
val (userCaptor, emailCaptor, templateCaptor) = argumentCaptor<User, String, EmailTemplate>()
verify(emailService).sendTemplatedEmail(
userCaptor.capture(),
emailCaptor.capture(),
templateCaptor.capture()
)Argument captors for larger numbers of parameters using holder classes.
/**
* Creates 4 KArgumentCaptors for given types
* @param a KClass for first type (defaults to reified A::class)
* @param b KClass for second type (defaults to reified B::class)
* @param c KClass for third type (defaults to reified C::class)
* @param d KClass for fourth type (defaults to reified D::class)
* @returns ArgumentCaptorHolder4 containing 4 KArgumentCaptors
*/
inline fun <reified A : Any, reified B : Any, reified C : Any, reified D : Any> argumentCaptor(
a: KClass<A> = A::class,
b: KClass<B> = B::class,
c: KClass<C> = C::class,
d: KClass<D> = D::class
): ArgumentCaptorHolder4<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>, KArgumentCaptor<D>>
/**
* Creates 5 KArgumentCaptors for given types
* @param a KClass for first type (defaults to reified A::class)
* @param b KClass for second type (defaults to reified B::class)
* @param c KClass for third type (defaults to reified C::class)
* @param d KClass for fourth type (defaults to reified D::class)
* @param e KClass for fifth type (defaults to reified E::class)
* @returns ArgumentCaptorHolder5 containing 5 KArgumentCaptors
*/
inline fun <reified A : Any, reified B : Any, reified C : Any, reified D : Any, reified E : Any> argumentCaptor(
a: KClass<A> = A::class,
b: KClass<B> = B::class,
c: KClass<C> = C::class,
d: KClass<D> = D::class,
e: KClass<E> = E::class
): ArgumentCaptorHolder5<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>, KArgumentCaptor<D>, KArgumentCaptor<E>>Usage Examples:
import com.nhaarman.mockitokotlin2.*
// Four argument captors
val captors = argumentCaptor<String, Int, Boolean, Double>()
verify(complexService).processData(
captors.first.capture(),
captors.second.capture(),
captors.third.capture(),
captors.fourth.capture()
)
// Five argument captors with destructuring
val (nameCaptor, ageCaptor, activeCaptor, salaryCaptor, dateCaptor) =
argumentCaptor<String, Int, Boolean, Double, LocalDate>()Argument captors with immediate lambda evaluation for verification.
/**
* Creates a KArgumentCaptor with immediate lambda evaluation for fast verification
* @param f Lambda function applied to the created captor
* @returns KArgumentCaptor instance after applying the lambda
*/
inline fun <reified T : Any> argumentCaptor(f: KArgumentCaptor<T>.() -> Unit): KArgumentCaptor<T>Usage Examples:
import com.nhaarman.mockitokotlin2.*
// Captor with immediate verification
val userCaptor = argumentCaptor<User> {
verify(userService).saveUser(capture())
// Can access captured values immediately
assertThat(firstValue.email).isNotEmpty()
}Special argument captors for nullable types.
/**
* Creates a KArgumentCaptor for nullable type
* @returns KArgumentCaptor instance for capturing nullable arguments of type T
*/
inline fun <reified T : Any> nullableArgumentCaptor(): KArgumentCaptor<T?>
/**
* Creates a KArgumentCaptor for nullable type with immediate lambda evaluation
* @param f Lambda function applied to the created captor
* @returns KArgumentCaptor instance for nullable type after applying the lambda
*/
inline fun <reified T : Any> nullableArgumentCaptor(f: KArgumentCaptor<T?>.() -> Unit): KArgumentCaptor<T?>Usage Examples:
import com.nhaarman.mockitokotlin2.*
// Nullable argument captor
val nullableUserCaptor = nullableArgumentCaptor<User>()
verify(userService).updateUser(nullableUserCaptor.capture())
val capturedUser = nullableUserCaptor.firstValue // Can be null
// Nullable captor with lambda
val nullableCaptor = nullableArgumentCaptor<String> {
verify(service).processOptionalData(capture())
// Handle null case
firstValue?.let {
assertThat(it).isNotEmpty()
}
}Utility function for capturing arguments directly.
/**
* Alias for ArgumentCaptor.capture() with null safety
* @param captor The ArgumentCaptor to use for capturing
* @returns Captured value or created instance if null
*/
inline fun <reified T : Any> capture(captor: ArgumentCaptor<T>): TUsage Examples:
import com.nhaarman.mockitokotlin2.*
import org.mockito.ArgumentCaptor
// Using with standard Mockito ArgumentCaptor
val javaCaptor = ArgumentCaptor.forClass(User::class.java)
verify(userService).saveUser(capture(javaCaptor))
val capturedUser = javaCaptor.valueKotlin wrapper for ArgumentCaptor providing enhanced functionality.
/**
* Kotlin wrapper for ArgumentCaptor with enhanced functionality and null safety
*/
class KArgumentCaptor<out T : Any?>(
private val captor: ArgumentCaptor<T>,
private val tClass: KClass<*>
) {
/**
* The first captured value of the argument
* @throws IndexOutOfBoundsException if the value is not available
*/
val firstValue: T
/**
* The second captured value of the argument
* @throws IndexOutOfBoundsException if the value is not available
*/
val secondValue: T
/**
* The third captured value of the argument
* @throws IndexOutOfBoundsException if the value is not available
*/
val thirdValue: T
/**
* The last captured value of the argument
* @throws IndexOutOfBoundsException if the value is not available
*/
val lastValue: T
/**
* All captured values as a list
*/
val allValues: List<T>
/**
* Captures an argument for the associated method parameter
* @returns Captured value or created instance if null
*/
fun capture(): T
}Usage Examples:
import com.nhaarman.mockitokotlin2.*
val userCaptor = argumentCaptor<User>()
// Capture multiple calls
verify(userService, times(3)).saveUser(userCaptor.capture())
// Access different captured values
val firstUser = userCaptor.firstValue
val secondUser = userCaptor.secondValue
val thirdUser = userCaptor.thirdValue
val lastUser = userCaptor.lastValue
// Access all captured values
val allUsers = userCaptor.allValues
assertThat(allUsers).hasSize(3)
// Verify properties of captured arguments
assertThat(firstUser.email).contains("@")
assertThat(allUsers).allMatch { it.age >= 18 }Helper classes for managing multiple argument captors.
/**
* Holder class for 4 argument captors with component access
*/
class ArgumentCaptorHolder4<out A, out B, out C, out D>(
val first: A,
val second: B,
val third: C,
val fourth: D
) {
operator fun component1(): A
operator fun component2(): B
operator fun component3(): C
operator fun component4(): D
}
/**
* Holder class for 5 argument captors with component access
*/
class ArgumentCaptorHolder5<out A, out B, out C, out D, out E>(
val first: A,
val second: B,
val third: C,
val fourth: D,
val fifth: E
) {
operator fun component1(): A
operator fun component2(): B
operator fun component3(): C
operator fun component4(): D
operator fun component5(): E
}Usage Examples:
import com.nhaarman.mockitokotlin2.*
// Using holder classes with destructuring
val (nameCaptor, ageCaptor, emailCaptor, activeCaptor) =
argumentCaptor<String, Int, String, Boolean>()
verify(userService).createUser(
nameCaptor.capture(),
ageCaptor.capture(),
emailCaptor.capture(),
activeCaptor.capture()
)
// Access via properties
val holder = argumentCaptor<String, Int, String, Boolean>()
verify(userService).createUser(
holder.first.capture(),
holder.second.capture(),
holder.third.capture(),
holder.fourth.capture()
)Extension properties for standard Mockito ArgumentCaptor to match KArgumentCaptor functionality.
/**
* Extension property for first captured value
*/
val <T> ArgumentCaptor<T>.firstValue: T
/**
* Extension property for second captured value
*/
val <T> ArgumentCaptor<T>.secondValue: T
/**
* Extension property for third captured value
*/
val <T> ArgumentCaptor<T>.thirdValue: T
/**
* Extension property for last captured value
*/
val <T> ArgumentCaptor<T>.lastValue: TUsage Examples:
import com.nhaarman.mockitokotlin2.*
import org.mockito.ArgumentCaptor
// Using extensions with standard ArgumentCaptor
val javaCaptor = ArgumentCaptor.forClass(String::class.java)
verify(service, times(3)).processString(javaCaptor.capture())
val firstString = javaCaptor.firstValue
val lastString = javaCaptor.lastValue
val allStrings = javaCaptor.allValues// From org.mockito
class ArgumentCaptor<T>
interface KClass<T>
// From mockito-kotlin
class KArgumentCaptor<out T : Any?>(
private val captor: ArgumentCaptor<T>,
private val tClass: KClass<*>
) {
val firstValue: T
val secondValue: T
val thirdValue: T
val lastValue: T
val allValues: List<T>
fun capture(): T
}
class ArgumentCaptorHolder4<out A, out B, out C, out D>(
val first: A,
val second: B,
val third: C,
val fourth: D
)
class ArgumentCaptorHolder5<out A, out B, out C, out D, out E>(
val first: A,
val second: B,
val third: C,
val fourth: D,
val fifth: E
)Install with Tessl CLI
npx tessl i tessl/maven-com-nhaarman-mockitokotlin2--mockito-kotlin