mocking library for Kotlin

Overview

mockk kotlin

Gitter Relase Version Change log codecov Android Matrix tests Open Source Helpers

Kotlin Academy articles

Check the series of articles "Mocking is not rocket science" at Kt. Academy describing MockK from the very basics of mocking up to description of all advanced features.

Spring support

Kotlin version support

From version 1.10.0 MockK does not support Kotlin 1.2.*

Known issues

  • PowerMock needs a workaround to run together with MockK #79. (not sure after workaround if it is generally usable or not, please somebody report it)
  • Inline functions cannot be mocked: see the discussion on this issue

Table of contents:

  • auto-gen TOC: {:toc}

Examples, guides & articles

Japanese guides and articles

Chinese guides and articles

Installation

All you need to get started is just to add a dependency to MockK library.

Gradle/maven dependency

Approach Instruction
Gradle    
testImplementation "io.mockk:mockk:{version}"
Gradle (Kotlin DSL)    
testImplementation("io.mockk:mockk:{version}")
Maven
<dependency>
    <groupId>io.mockk</groupId>
    <artifactId>mockk</artifactId>
    <version>{version}</version>
    <scope>test</scope>
</dependency>
android Unit    
testImplementation "io.mockk:mockk:{version}"
android Instrumented    
androidTestImplementation "io.mockk:mockk-android:{version}"
Common multiplatform    
testImplementation "io.mockk:mockk-common:{version}"

where {version} corresponds to version as below:

  • Kotlin 1.3+ and Coroutines 1.0+ Version: Download
  • Kotlin 1.2 Compatible Version: Download

DSL examples

Simplest example. By default mocks are strict, so you need to provide some behaviour.

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

Annotations

You can use annotations to simplify the creation of mock objects:

class TrafficSystem {
  lateinit var car1: Car
  
  lateinit var car2: Car
  
  lateinit var car3: Car
}

class CarTest {
  @MockK
  lateinit var car1: Car

  @RelaxedMockK
  lateinit var car2: Car

  @MockK(relaxUnitFun = true)
  lateinit var car3: Car

  @SpyK
  var car4 = Car()
  
  @InjectMockKs
  var trafficSystem = TrafficSystem()
  
  @Before
  fun setUp() = MockKAnnotations.init(this, relaxUnitFun = true) // turn relaxUnitFun on for all mocks

  @Test
  fun calculateAddsValues1() {
      // ... use car1, car2, car3 and car4
  }
}

Injection first tries to match properties by name, then by class or superclass. Check the lookupType parameter for customization.

Properties are injected even if private is applied. Constructors for injection are selected from the biggest number of arguments to lowest.

@InjectMockKs by default is injecting only lateinit vars or vars that are not assigned. To change this, use overrideValues = true. This would assign the value even if it is already somehow initialized. To inject vals, use injectImmutable = true. For a shorter notation use @OverrideMockKs which does the same as @InjectMockKs by default, but turns these two flags on.

JUnit5

In JUnit5 you can use MockKExtension to initialize your mocks.

@ExtendWith(MockKExtension::class)
class CarTest {
  @MockK
  lateinit var car1: Car

  @RelaxedMockK
  lateinit var car2: Car

  @MockK(relaxUnitFun = true)
  lateinit var car3: Car

  @SpyK
  var car4 = Car()

  @Test
  fun calculateAddsValues1() {
      // ... use car1, car2, car3 and car4
  }
}

Additionally, it adds the possibility to use @MockK and @RelaxedMockK on test function parameters:

@Test
fun calculateAddsValues1(@MockK car1: Car, @RelaxedMockK car2: Car) {
  // ... use car1 and car2
}

Spy

Spies allow to mix mocks and real objects.

val car = spyk(Car()) // or spyk<Car>() to call default constructor

car.drive(Direction.NORTH) // returns whatever real function of Car returns

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

Note: the spy object is a copy of a passed object.

Relaxed mock

A relaxed mock is the mock that returns some simple value for all functions. This allows to skip specifying behavior for each case, while still allowing to stub things you need. For reference types, chained mocks are returned.

val car = mockk<Car>(relaxed = true)

car.drive(Direction.NORTH) // returns null

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

Note: relaxed mocking is working badly with generic return types. A class cast exception is usually thrown in this case. Opt for stubbing manually in case of a generic return type.

Workaround:

val func = mockk<() -> Car>(relaxed = true) // in this case invoke function has generic return type

// this line is workaround, without it the relaxed mock would throw a class cast exception on the next line
every { func() } returns Car() // or you can return mockk() for example 

func()

Mock relaxed for functions returning Unit

In case you would like Unit returning functions to be relaxed, you can use relaxUnitFun = true as an argument to the mockk function, @MockKannotation or MockKAnnotations.init function.

Function:

mockk<MockCls>(relaxUnitFun = true)

Annotation:

@MockK(relaxUnitFun = true)
lateinit var mock1: RurfMockCls
init {
    MockKAnnotations.init(this)
}

MockKAnnotations.init:

@MockK
lateinit var mock2: RurfMockCls
init {
    MockKAnnotations.init(this, relaxUnitFun = true)
}

Object mocks

Objects can be transformed to mocks in the following way:

object MockObj {
  fun add(a: Int, b: Int) = a + b
}

mockkObject(MockObj) // applies mocking to an Object

assertEquals(3, MockObj.add(1, 2))

every { MockObj.add(1, 2) } returns 55

assertEquals(55, MockObj.add(1, 2))

To revert back, use unmockkAll or unmockkObject:

@Before
fun beforeTests() {
    mockkObject(MockObj)
    every { MockObj.add(1,2) } returns 55
}

@Test
fun willUseMockBehaviour() {
    assertEquals(55, MockObj.add(1,2))
}

@After
fun afterTests() {
    unmockkAll()
    // or unmockkObject(MockObj)
}

Despite the Kotlin language limits, you can create new instances of objects if required by testing logic:

val newObjectMock = mockk<MockObj>()

Class mock

Sometimes you need a mock of arbitrary class. Use mockkClass in those cases.

val car = mockkClass(Car::class)

every { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

verify { car.drive(Direction.NORTH) }

Enumeration mocks

Enums can be mocked using mockkObject:

enum class Enumeration(val goodInt: Int) {
    CONSTANT(35),
    OTHER_CONSTANT(45);
}

mockkObject(Enumeration.CONSTANT)
every { Enumeration.CONSTANT.goodInt } returns 42
assertEquals(42, Enumeration.CONSTANT.goodInt)

Constructor mocks

Sometimes, especially in code you don't own, you need to mock newly created objects. For this purpose, the following constructs are provided:

class MockCls {
  fun add(a: Int, b: Int) = a + b
}

mockkConstructor(MockCls::class)

every { anyConstructed<MockCls>().add(1, 2) } returns 4

assertEquals(4, MockCls().add(1, 2)) // note new object is created

verify { anyConstructed<MockCls>().add(1, 2) }

The basic idea is that just after the constructor of the mocked class is executed (any of them), objects become a constructed mock. Mocking behavior of such a mock is connected to the special prototype mock denoted by anyConstructed<MockCls>(). There is one instance per class of such a prototype mock. Call recording also happens to the prototype mock. If no behavior for the function is specified then the original function is executed.

In case a class has more than one constructor, they can be mocked separately:

class MockCls(private val a: Int = 0) {
  constructor(x: String) : this(x.toInt())  
  fun add(b: Int) = a + b
}

mockkConstructor(MockCls::class)

every { constructedWith<MockCls>().add(1) } returns 2
every { 
    constructedWith<MockCls>(OfTypeMatcher<String>(String::class)).add(2) // Mocks the constructor taking a String
} returns 3
every {
    constructedWith<MockCls>(EqMatcher(4)).add(any()) // Mocks the constructor taking an Int
} returns 4

assertEquals(2, MockCls().add(1))
assertEquals(3, MockCls("2").add(2))
assertEquals(4, MockCls(4).add(7))

verify { 
    constructedWith<MockCls>().add(1)
    constructedWith<MockCls>("2").add(2)
    constructedWith<MockCls>(EqMatcher(4)).add(7)
}

Note that in this case, a prototype mock is created for every set of argument matchers passed to constructedWith.

Partial argument matching

You can mix both regular arguments and matchers:

val car = mockk<Car>()

every { 
  car.recordTelemetry(
    speed = more(50),
    direction = Direction.NORTH, // here eq() is used
    lat = any(),
    long = any()
  )
} returns Outcome.RECORDED

car.recordTelemetry(60, Direction.NORTH, 51.1377382, 17.0257142)

verify { car.recordTelemetry(60, Direction.NORTH, 51.1377382, 17.0257142) }

confirmVerified(car)

Chained calls

You can stub chains of calls:

val car = mockk<Car>()

every { car.door(DoorType.FRONT_LEFT).windowState() } returns WindowState.UP

car.door(DoorType.FRONT_LEFT) // returns chained mock for Door
car.door(DoorType.FRONT_LEFT).windowState() // returns WindowState.UP

verify { car.door(DoorType.FRONT_LEFT).windowState() }

confirmVerified(car)

Note: in case the function's return type is generic then the information about the actual type is gone. To make chained calls work, additional information is required. Most of the time the framework will catch the cast exception and do autohinting. In the case it is explicitly required, use hint before making the next call.

every { obj.op2(1, 2).hint(Int::class).op1(3, 4) } returns 5

Hierarchical mocking

From version 1.9.1 mocks may be chained into hierarchies:

interface AddressBook {
    val contacts: List<Contact>
}

interface Contact {
    val name: String
    val telephone: String
    val address: Address
}

interface Address {
    val city: String
    val zip: String
}

val addressBook = mockk<AddressBook> {
    every { contacts } returns listOf(
        mockk {
            every { name } returns "John"
            every { telephone } returns "123-456-789"
            every { address.city } returns "New-York"
            every { address.zip } returns "123-45"
        },
        mockk {
            every { name } returns "Alex"
            every { telephone } returns "789-456-123"
            every { address } returns mockk {
                every { city } returns "Wroclaw"
                every { zip } returns "543-21"
            }
        }
    )
}

Capturing

You can capture an argument to a CapturingSlot or MutableList:

val car = mockk<Car>()

val slot = slot<Double>()
val list = mutableListOf<Double>()

every {
  car.recordTelemetry(
    speed = capture(slot), // makes mock match call with any value for `speed` and record it in a slot
    direction = Direction.NORTH // makes mock and capturing only match calls with specific `direction`. Use `any()` to match calls with any `direction`
  )
} answers {
  println(slot.captured)

  Outcome.RECORDED
}


every {
  car.recordTelemetry(
    speed = capture(list),
    direction = Direction.SOUTH
  )
} answers {
  println(list)

  Outcome.RECORDED
}

car.recordTelemetry(speed = 15, direction = Direction.NORTH) // prints 15
car.recordTelemetry(speed = 16, direction = Direction.SOUTH) // prints 16

verify(exactly = 2) { car.recordTelemetry(speed = or(15, 16), direction = any()) }

confirmVerified(car)

Verification atLeast, atMost or exactly times

You can check the call count with the atLeast, atMost or exactly parameters:

val car = mockk<Car>(relaxed = true)

car.accelerate(fromSpeed = 10, toSpeed = 20)
car.accelerate(fromSpeed = 10, toSpeed = 30)
car.accelerate(fromSpeed = 20, toSpeed = 30)

// all pass
verify(atLeast = 3) { car.accelerate(allAny()) }
verify(atMost  = 2) { car.accelerate(fromSpeed = 10, toSpeed = or(20, 30)) }
verify(exactly = 1) { car.accelerate(fromSpeed = 10, toSpeed = 20) }
verify(exactly = 0) { car.accelerate(fromSpeed = 30, toSpeed = 10) } // means no calls were performed

confirmVerified(car)

Verification order

  • verifyAll verifies that all calls happened without checking their order.
  • verifySequence verifies that the calls happened in a specified sequence.
  • verifyOrder verifies that calls happened in a specific order.
  • wasNot Called verifies that the mock or the list of mocks was not called at all.
class MockedClass {
    fun sum(a: Int, b: Int) = a + b
}

val obj = mockk<MockedClass>()
val slot = slot<Int>()

every {
    obj.sum(any(), capture(slot))
} answers {
    1 + firstArg<Int>() + slot.captured
}

obj.sum(1, 2) // returns 4
obj.sum(1, 3) // returns 5
obj.sum(2, 2) // returns 5

verifyAll {
    obj.sum(1, 3)
    obj.sum(1, 2)
    obj.sum(2, 2)
}

verifySequence {
    obj.sum(1, 2)
    obj.sum(1, 3)
    obj.sum(2, 2)
}

verifyOrder {
    obj.sum(1, 2)
    obj.sum(2, 2)
}

val obj2 = mockk<MockedClass>()
val obj3 = mockk<MockedClass>()
verify {
    listOf(obj2, obj3) wasNot Called
}

confirmVerified(obj)

Verification confirmation

To double check that all calls were verified by verify... constructs, you can use confirmVerified:

confirmVerified(mock1, mock2)

It does not make much sense to use it for verifySequence and verifyAll as these verification methods already exhaustively cover all calls with verification.

It will throw an exception in case there are some calls left without verification.

Some calls may be skipped from such confirmation, check the next section for more details.

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK
every { car.drive(Direction.SOUTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK
car.drive(Direction.SOUTH) // returns OK

verify {
    car.drive(Direction.SOUTH)
    car.drive(Direction.NORTH)
}

confirmVerified(car) // makes sure all calls were covered with verification

Recording exclusions

To exclude some not so important calls from being recorded you can use excludeRecords:

excludeRecords { mock.operation(any(), 5) }

All matching calls will be excluded from recording. This may be useful in case you are using exhaustive verification: verifyAll, verifySequence or confirmVerified.

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK
every { car.drive(Direction.SOUTH) } returns Outcome.OK

excludeRecords { car.drive(Direction.SOUTH) }

car.drive(Direction.NORTH) // returns OK
car.drive(Direction.SOUTH) // returns OK

verify {
    car.drive(Direction.NORTH)
}

confirmVerified(car) // car.drive(Direction.SOUTH) was excluded, so confirmation is fine with only car.drive(Direction.NORTH)

Verification timeout

To verify concurrent operations, you can use timeout = xxx:

mockk<MockCls> {
    every { sum(1, 2) } returns 4

    Thread {
        Thread.sleep(2000)
        sum(1, 2)
    }.start()

    verify(timeout = 3000) { sum(1, 2) }
}

This will wait until one of two following states: either verification is passed or timeout is reached.

Returning Unit

If the function is returning Unit you can use the justRun construct:

class MockedClass {
    fun sum(a: Int, b: Int): Unit {
        println(a + b)
    }
}

val obj = mockk<MockedClass>()

justRun { obj.sum(any(), 3) }

obj.sum(1, 1)
obj.sum(1, 2)
obj.sum(1, 3)

verify {
    obj.sum(1, 1)
    obj.sum(1, 2)
    obj.sum(1, 3)
}

Another ways to write justRun { obj.sum(any(), 3) } is:

  • every { obj.sum(any(), 3) } just Runs
  • every { obj.sum(any(), 3) } returns Unit
  • every { obj.sum(any(), 3) } answers { Unit }

Coroutines

To mock coroutines you need to add another dependency to the support library.

Gradle
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:x.x"
Maven
<dependency>
    <groupId>org.jetbrains.kotlinx</groupId>
    <artifactId>kotlinx-coroutines-core</artifactId>
    <version>x.x</version>
    <scope>test</scope>
</dependency>

Then you can use coEvery, coVerify, coMatch, coAssert, coRun, coAnswers or coInvoke to mock suspend functions.

val car = mockk<Car>()

coEvery { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

coVerify { car.drive(Direction.NORTH) }

Extension functions

There are three cases of extension function:

  • class wide
  • object wide
  • module wide

In case of an object or a class, you can mock extension functions just by creating a regular mockk:

data class Obj(val value: Int)

class Ext {
    fun Obj.extensionFunc() = value + 5
}

with(mockk<Ext>()) {
    every {
        Obj(5).extensionFunc()
    } returns 11

    assertEquals(11, Obj(5).extensionFunc())

    verify {
        Obj(5).extensionFunc()
    }
}

To mock module wide extension functions you need to build mockkStatic(...) with as argument the module's class name. For example "pkg.FileKt" for module File.kt in the pkg package.

data class Obj(val value: Int)

// declared in File.kt ("pkg" package)
fun Obj.extensionFunc() = value + 5

mockkStatic("pkg.FileKt")

every {
    Obj(5).extensionFunc()
} returns 11

assertEquals(11, Obj(5).extensionFunc())

verify {
    Obj(5).extensionFunc()
}

On jvm environments you can replace the class name with a function reference:

mockkStatic(Obj::extensionFunc)

Note that this will mock the whole pkg.FileKt class, and not just extensionFunc.

This syntax also applies for extension properties:

val Obj.squareValue get() = value * value

mockkStatic(Obj::squareValue)

If @JvmName is used, specify it as a class name.

KHttp.kt:

@file:JvmName("KHttp")

package khttp
// ... KHttp code 

Testing code:

mockkStatic("khttp.KHttp")

Sometimes you need to know a little bit more to mock an extension function. For example File.endsWith() extension function has a totally unpredictable classname:

   mockkStatic("kotlin.io.FilesKt__UtilsKt")
   every { File("abc").endsWith(any<String>()) } returns true
   println(File("abc").endsWith("abc"))

This is standard Kotlin behaviour that may be unpredictable. Use Tools -> Kotlin -> Show Kotlin Bytecode or check .class files in JAR archive to detect such names.

Varargs

From version 1.9.1 more extended vararg handling is possible:

    interface ClsWithManyMany {
        fun manyMany(vararg x: Any): Int
    }

    val obj = mockk<ClsWithManyMany>()

    every { obj.manyMany(5, 6, *varargAll { it == 7 }) } returns 3

    println(obj.manyMany(5, 6, 7)) // 3
    println(obj.manyMany(5, 6, 7, 7)) // 3
    println(obj.manyMany(5, 6, 7, 7, 7)) // 3

    every { obj.manyMany(5, 6, *anyVararg(), 7) } returns 4

    println(obj.manyMany(5, 6, 1, 7)) // 4
    println(obj.manyMany(5, 6, 2, 3, 7)) // 4
    println(obj.manyMany(5, 6, 4, 5, 6, 7)) // 4

    every { obj.manyMany(5, 6, *varargAny { nArgs > 5 }, 7) } returns 5

    println(obj.manyMany(5, 6, 4, 5, 6, 7)) // 5
    println(obj.manyMany(5, 6, 4, 5, 6, 7, 7)) // 5

    every {
        obj.manyMany(5, 6, *varargAny {
            if (position < 3) it == 3 else it == 4
        }, 7)
    } returns 6
    
    println(obj.manyMany(5, 6, 3, 4, 7)) // 6
    println(obj.manyMany(5, 6, 3, 4, 4, 7)) // 6

Private functions mocking / dynamic calls

In case you have a need to mock private functions, you can do it via a dynamic call.

class Car {
    fun drive() = accelerate()

    private fun accelerate() = "going faster"
}

val mock = spyk<Car>(recordPrivateCalls = true)

every { mock["accelerate"]() } returns "going not so fast"

assertEquals("going not so fast", mock.drive())

verifySequence {
    mock.drive()
    mock["accelerate"]()
}

In case you want private calls to be verified, you should create a spyk with recordPrivateCalls = true

Additionally, a more verbose syntax allows you to get and set properties, combined with the same dynamic calls:

val mock = spyk(Team(), recordPrivateCalls = true)

every { mock getProperty "speed" } returns 33
every { mock setProperty "acceleration" value less(5) } just runs
justRun { mock invokeNoArgs "privateMethod" }
every { mock invoke "openDoor" withArguments listOf("left", "rear") } returns "OK"

verify { mock getProperty "speed" }
verify { mock setProperty "acceleration" value less(5) }
verify { mock invoke "openDoor" withArguments listOf("left", "rear") }

Property backing fields

You can access the backing fields via fieldValue and use value for value being set.

Note: in the examples below, we use propertyType to specify the type of the fieldValue. This is needed because it is possible to capture the type automatically for the getter. Use nullablePropertyType to specify a nullable type.

val mock = spyk(MockCls(), recordPrivateCalls = true)

every { mock.property } answers { fieldValue + 6 }
every { mock.property = any() } propertyType Int::class answers { fieldValue += value }
every { mock getProperty "property" } propertyType Int::class answers { fieldValue + 6 }
every { mock setProperty "property" value any<Int>() } propertyType Int::class answers  { fieldValue += value }
every {
    mock.property = any()
} propertyType Int::class answers {
    fieldValue = value + 1
} andThen {
    fieldValue = value - 1
}

Multiple interfaces

Adding additional behaviours via interfaces and stubbing them:

val spy = spyk(System.out, moreInterfaces = *arrayOf(Runnable::class))

spy.println(555)

every {
    (spy as Runnable).run()
} answers {
    (self as PrintStream).println("Run! Run! Run!")
}

val thread = Thread(spy as Runnable)
thread.start()
thread.join()

Mocking Nothing

Nothing special here. If you have a function returning Nothing:

fun quit(status: Int): Nothing {
    exitProcess(status)
}

Then you can for example throw an exception as behaviour:

every { quit(1) } throws Exception("this is a test")

Clearing vs Unmocking

  • clear - deletes internal state of objects associated with mock resulting in empty object
  • unmock - re-assigns transformation of classes back to original state prior to mock

Matcher extensibility

A very simple way is to create new matchers by attaching a function to MockKMatcherScope or MockKVerificationScope and using the match function:

    fun MockKMatcherScope.seqEq(seq: Sequence<String>) = match<Sequence<String>> {
        it.toList() == seq.toList()
    }

Also, it is possible to create more advanced matchers by implementing the Matcher interface.

Custom matchers

Example of a custom matcher that compares list without order:

@Test
fun test() {
    class MockCls {
        fun op(a: List<Int>) = a.reversed()
    }

    val mock = mockk<MockCls>()

    every { mock.op(any()) } returns listOf(5, 6, 9)

    println(mock.op(listOf(1, 2, 3)))

    verify { mock.op(matchListWithoutOrder(3, 2, 1)) }

}

data class ListWithoutOrderMatcher<T>(
    val expectedList: List<T>,
    val refEq: Boolean
) : Matcher<List<T>> {
    val map = buildCountsMap(expectedList, refEq)

    override fun match(arg: List<T>?): Boolean {
        if (arg == null) return false
        return buildCountsMap(arg, refEq) == map
    }

    private fun buildCountsMap(list: List<T>, ref: Boolean): Map<Any?, Int> {
        val map = mutableMapOf<Any?, Int>()

        for (item in list) {
            val key = when {
                item == null -> nullKey
                refEq -> InternalPlatform.ref(item)
                else -> item
            }
            map.compute(key, { _, value -> (value ?: 0) + 1 })
        }

        return map
    }

    override fun toString() = "matchListWithoutOrder($expectedList)"

    @Suppress("UNCHECKED_CAST")
    override fun substitute(map: Map<Any, Any>): Matcher<List<T>> {
        return copy(expectedList = expectedList.map { map.getOrDefault(it as Any?, it) } as List<T>)
    }

    companion object {
        val nullKey = Any()
    }
}

inline fun <reified T : List<E>, E : Any> MockKMatcherScope.matchListWithoutOrder(
    vararg items: E,
    refEq: Boolean = true
): T = match(ListWithoutOrderMatcher(listOf(*items), refEq))

Settings file

To adjust parameters globally, there is a possibility to specify a few settings in a resource file.

How to use:

  1. Create a io/mockk/settings.properties file in src/main/resources.
  2. Put one of following options:
relaxed=true|false
relaxUnitFun=true|false
recordPrivateCalls=true|false
stackTracesOnVerify=true|false
stackTracesAlignment=left|center

Where stackTracesAlignment determines whether to align the stack traces displayed when showing recorded calls to the center (default) or to the left (more consistent with usual JVM stackTraces).

DSL tables

Here are a few tables to help you master the DSL.

Top level functions

Function Description
mockk<T>(...) builds a regular mock
spyk<T>() builds a spy using the default constructor
spyk(obj) builds a spy by copying from obj
slot creates a capturing slot
every starts a stubbing block
coEvery starts a stubbing block for coroutines
verify starts a verification block
coVerify starts a verification block for coroutines
verifyAll starts a verification block that should include all calls
coVerifyAll starts a verification block that should include all calls for coroutines
verifyOrder starts a verification block that checks the order
coVerifyOrder starts a verification block that checks the order for coroutines
verifySequence starts a verification block that checks whether all calls were made in a specified sequence
coVerifySequence starts a verification block that checks whether all calls were made in a specified sequence for coroutines
excludeRecords exclude some calls from being recorded
confirmVerified confirms that all recorded calls were verified
clearMocks clears specified mocks
registerInstanceFactory allows you to redefine the way of instantiation for certain object
mockkClass builds a regular mock by passing the class as parameter
mockkObject makes an object an object mock or clears it if was already transformed
unmockkObject makes an object mock back to a regular object
mockkStatic makes a static mock out of a class or clears it if it was already transformed
unmockkStatic makes a static mock back to a regular class
clearStaticMockk clears a static mock
mockkConstructor makes a constructor mock out of a class or clears it if it was already transformed
unmockkConstructor makes a constructor mock back to a regular class
clearConstructorMockk clears the constructor mock
unmockkAll unmocks object, static and constructor mocks
clearAllMocks clears regular, object, static and constructor mocks

Matchers

By default, simple arguments are matched using eq()

Matcher Description
any() matches any argument
allAny() special matcher that uses any() instead of eq() for matchers that are provided as simple arguments
isNull() checks if the value is null
isNull(inverse=true) checks if the value is not null
ofType(type) checks if the value belongs to the type
match { it.startsWith("string") } matches via the passed predicate
coMatch { it.startsWith("string") } matches via the passed coroutine predicate
matchNullable { it?.startsWith("string") } matches nullable value via the passed predicate
coMatchNullable { it?.startsWith("string") } matches nullable value via the passed coroutine predicate
eq(value) matches if the value is equal to the provided value via the deepEquals function
eq(value, inverse=true) matches if the value is not equal to the provided value via the deepEquals function
neq(value) matches if the value is not equal to the provided value via deepEquals function
refEq(value) matches if the value is equal to the provided value via reference comparison
refEq(value, inverse=true) matches if the value is not equal to the provided value via reference comparison
nrefEq(value) matches if the value is not equal to the provided value via reference comparison
cmpEq(value) matches if the value is equal to the provided value via the compareTo function
less(value) matches if the value is less than the provided value via the compareTo function
more(value) matches if the value is more than the provided value via the compareTo function
less(value, andEquals=true) matches if the value is less than or equal to the provided value via the compareTo function
more(value, andEquals=true) matches if the value is more than or equal to the provided value via the compareTo function
range(from, to, fromInclusive=true, toInclusive=true) matches if the value is in range via the compareTo function
and(left, right) combines two matchers via a logical and
or(left, right) combines two matchers via a logical or
not(matcher) negates the matcher
capture(slot) captures a value to a CapturingSlot
capture(mutableList) captures a value to a list
captureNullable(mutableList) captures a value to a list together with null values
captureLambda() captures a lambda
captureCoroutine() captures a coroutine
invoke(...) calls a matched argument
coInvoke(...) calls a matched argument for a coroutine
hint(cls) hints the next return type in case it's gotten erased
anyVararg() matches any elements in a vararg
varargAny(matcher) matches if any element is matching the matcher
varargAll(matcher) matches if all elements are matching the matcher
any...Vararg() matches any elements in vararg (specific to primitive type)
varargAny...(matcher) matches if any element is matching the matcher (specific to the primitive type)
varargAll...(matcher) matches if all elements are matching the matcher (specific to the primitive type)

A few special matchers available in verification mode only:

Matcher Description
withArg { code } matches any value and allows to execute some code
withNullableArg { code } matches any nullable value and allows to execute some code
coWithArg { code } matches any value and allows to execute some coroutine code
coWithNullableArg { code } matches any nullable value and allows to execute some coroutine code

Validators

Validator Description
verify { mock.call() } Do unordered verification that a call was performed
verify(inverse=true) { mock.call() } Do unordered verification that a call was not performed
verify(atLeast=n) { mock.call() } Do unordered verification that a call was performed at least n times
verify(atMost=n) { mock.call() } Do unordered verification that a call was performed at most n times
verify(exactly=n) { mock.call() } Do unordered verification that a call was performed exactly n times
verifyAll { mock.call1(); mock.call2() } Do unordered verification that only the specified calls were executed for the mentioned mocks
verifyOrder { mock.call1(); mock.call2() } Do verification that the sequence of calls went one after another
verifySequence { mock.call1(); mock.call2() } Do verification that only the specified sequence of calls were executed for the mentioned mocks
verify { mock wasNot Called } Do verification that a mock was not called
verify { listOf(mock1, mock2) wasNot Called } Do verification that a list of mocks were not called

Answers

An Answer can be followed up by one or more additional answers.

Answer Description
returns value specify that the matched call returns a specified value
returnsMany list specify that the matched call returns a value from the list, with subsequent calls returning the next element
throws ex specify that the matched call throws an exception
answers { code } specify that the matched call answers with a code block scoped with answer scope
coAnswers { code } specify that the matched call answers with a coroutine code block with answer scope
answers answerObj specify that the matched call answers with an Answer object
answers { nothing } specify that the matched call answers null
just Runs specify that the matched call is returning Unit (returns null)
propertyType Class specify the type of backing field accessor
nullablePropertyType Class specify the type of backing field accessor as a nullable type

Additional answer(s)

A next answer is returned on each consequent call and the last value is persisted. So this is similar to the returnsMany semantics.

Additional answer Description
andThen value specify that the matched call returns one specified value
andThenMany list specify that the matched call returns value from the list, returning each time next element
andThenThrows ex specify that the matched call throws an exception
andThen { code } specify that the matched call answers with a code block scoped with answer scope
coAndThen { code } specify that the matched call answers with a coroutine code block with answer scope
andThenAnswer answerObj specify that the matched call answers with an Answer object
andThen { nothing } specify that the matched call answers null

Answer scope

Parameter Description
call a call object that consists of an invocation and a matcher
invocation contains information regarding the actual function invoked
matcher contains information regarding the matcher used to match the invocation
self reference to the object invocation made
method reference to the function invocation made
args reference to the arguments of invocation
nArgs number of invocation argument
arg(n) n-th argument
firstArg() first argument
secondArg() second argument
thirdArg() third argument
lastArg() last argument
captured() the last element in the list for convenience when capturing to a list
lambda<...>().invoke() call the captured lambda
coroutine<...>().coInvoke() call the captured coroutine
nothing null value for returning nothing as an answer
fieldValue accessor to the property backing field
fieldValueAny accessor to the property backing field with Any? type
value value being set casted to same type as the property backing field
valueAny value being set with Any? type
callOriginal calls the original function

Vararg scope

Parameter Description
position the position of an argument in vararg array
nArgs overall count of arguments in vararg array

Funding

You can also support this project by becoming a sponsor. Your logo will show up here with a link to your website.

Sponsors

Backers

Thank you to all our backers! 🙏

Contributors

This project exists thanks to all the people who contribute.

Getting Help

To ask questions, please use Stack Overflow or Gitter.

To report bugs, please use the GitHub project.

Comments
  • Feature: inline classes

    Feature: inline classes

    I am trying to use Kotlin's experimental inline class feature. I have an interface with a method accepting a parameter with an inline class type. In this case, every function throws an exception.

    Prerequisites

    My Kotlin version is: 1.3.0-rc-146

    • [x] I am running the latest version - 1.8.9.kotlin13
    • [x] I checked the documentation and found no answer
    • [x] I checked to make sure that this issue has not already been filed

    Expected Behavior

    I should be able to define every with any() in parameters.

    Current Behavior

    Test throws an exception.

    Failure Information (for bugs)

    See the exception details in Failure logs section.

    Steps to Reproduce

    This is a test case. I am running this with Kotlin 1.3.0-rc-146, kotlin-reflect 1.3.0-rc-146, JUnit 5.1.0, mockk 1.8.9.kotlin13.

    import io.mockk.every
    import io.mockk.mockk
    import org.junit.jupiter.api.Test
    
    class MockkFailingTest {
        @Test // fails
        fun `mockk test using any()`() {
            val mocked = mockk<TestMock>(relaxed = true)
            every { mocked.test(any()) } returns 1
        }
    
        @Test // passes
        fun `mockk test using hardcoded value`() {
            val mocked = mockk<TestMock>(relaxed = true)
            every { mocked.test(MyInlineType("123")) } returns 1
        }
    
    }
    
    inline class MyInlineType(val value: String)
    
    interface TestMock {
        fun test(value: MyInlineType): Int
    }
    

    Context

    Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

    • MockK version: 1.8.9.kotlin13
    • OS: Ubuntu 18.04
    • Kotlin version: 1.3.0-rc-146
    • JDK version: 1.8
    • JUnit version: 5.1.0
    • Type of test: unit test

    Failure Logs

    io.mockk.MockKException: Failed matching mocking signature for
    SignedCall(retValue=0, isRetValueMock=false, retType=class kotlin.Int, self=TestMock(#2), method=test-gNmuAAA(String), args=[null], invocationStr=TestMock(#2).test-gNmuAAA(null))
    left matchers: [any()]
    
    	at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:99)
    	at io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:38)
    	at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:30)
    	at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:45)
    	at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:47)
    	at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:25)
    	at io.mockk.MockKDsl.internalEvery(API.kt:93)
    	at io.mockk.MockKKt.every(MockK.kt:104)
    	at conduit.handler.LoginHandlerImplTest.mockk test(LoginHandlerImplTest.kt:79)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436)
    	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
    	at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
    	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
    	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
    	at java.util.Iterator.forEachRemaining(Iterator.java:116)
    	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
    	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
    	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
    	at java.util.Iterator.forEachRemaining(Iterator.java:116)
    	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
    	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
    	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
    	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
    	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    
    enhancement important 
    opened by alisabzevari 56
  • java.lang.InstantiationError when upgrading to Kotlin 1.7

    java.lang.InstantiationError when upgrading to Kotlin 1.7

    Java 17 + Kotlin 1.7 + Mockk 1.12.4/Spring Mockk 3.1.1

    java.lang.InstantiationError: com.example.demo.UpdateAccountResult
        at jdk.internal.reflect.GeneratedSerializationConstructorAccessor18.newInstance(Unknown Source)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
    

    It occurred whens using coEvery{} to do some stub, which returns a UpdateAccountResult.Success().

    Here UpdateAccountResult is a sealed class, it has some detailed result subclass/sub data classes.

    And UpdateAccountResult extends from a base abstract class like this.

    abstract class ApiBaseResult {
        @field:JsonProperty("SC")
        val statusCode: String? = null
    
        @field:JsonProperty("EC")
        val errorCode: String? = null
    
        @field:JsonProperty("EM")
        val errorMessage: String? = null
    }
    

    These codes are working well with Kotlin 1.6.21.

    opened by hantsy 55
  • Bug: MockKAgentException when creating a mock on >= Api level 28 due to missing 64 binaries

    Bug: MockKAgentException when creating a mock on >= Api level 28 due to missing 64 binaries

    Expected Behavior

    Expecting mocked instances to be initialised correctly.

    Current Behavior

    Currently, whenever a mock of a class is created a MockKAgentException is thrown (see stacktrace below) on api level 28 or greater. I don't seem to be having any issues on lower API levels.

    Steps to Reproduce

    1. Create a test case containing code to create a mock
    2. Run test

    Context

    • MockK version: 1.9.3
    • OS: >= API level 28
    • Kotlin version: 1.3.11
    • JDK version: 8
    • JUnit version: 4.12
    • Type of test: instrumented test

    Stack trace

    Caused by: io.mockk.proxy.MockKAgentException: MockK could not self-attach a jvmti agent to the current VM. This feature is required for inline mocking.
    This error occured due to an I/O error during the creation of this agent: java.io.IOException: No such file or directory
    
    Potentially, the current VM does not support the jvmti API correctly
    at io.mockk.proxy.android.AndroidMockKAgentFactory.init(AndroidMockKAgentFactory.kt:63)
    at io.mockk.impl.JvmMockKGateway.<init>(JvmMockKGateway.kt:46)
    at io.mockk.impl.JvmMockKGateway.<clinit>(JvmMockKGateway.kt:172)
    ... 33 more
    Caused by: java.io.IOException: No such file or directory
    at java.io.UnixFileSystem.createFileExclusively0(Native Method)
    at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:281)
    at java.io.File.createTempFile(File.java:2018)
    at java.io.File.createTempFile(File.java:2064)
    at io.mockk.proxy.android.JvmtiAgent.appendToBootstrapClassLoaderSearch(JvmtiAgent.kt:53)
    at io.mockk.proxy.android.AndroidMockKAgentFactory.init(AndroidMockKAgentFactory.kt:48)
    ... 35 more
    

    Minimal reproducible code (the gist of this issue)

    // -----------------------[ GRADLE DEFINITIONS ] -----------------------
    dependencies {
        androidTestImplementation "io.mockk:mockk-android:1.9.3"
    }
    // -----------------------[ YOUR CODE STARTS HERE ] -----------------------
    object MockHelper {
        fun mockIsEnabled(enabled: Boolean = false) {
    
            val mock: LocationChecker = mockk(relaxed = true) //failure here
    
            val component = DaggerTestAppComponent
                .builder()
                .testModule(TestModule(locationChecker = mock))
                .build()
    
            val application = Application.getApplication(InstrumentationRegistry.getTargetContext())
            application.appComponent = component
        }
    }
    
    @RunWith(AndroidJUnit4::class)
    class ScreenTest : BaseUITest() {
    
        @Before
        fun setUp() {
            MockHelper.mockIsEnabled(true)
        }
        
    }
    
    // -----------------------[ YOUR CODE ENDS HERE ] -----------------------
    
    bug ait important 
    opened by jtrollkarl 47
  • Feature: Add a way to mock a constructor with defined values

    Feature: Add a way to mock a constructor with defined values

    Prerequisites

    Please answer the following questions for yourself before submitting an issue.

    • [x] I am running the latest version
    • [x] I checked the documentation and found no answer
    • [x] I checked to make sure that this issue has not already been filed

    Expected Behavior

    Actually we can mock constructors but there is no way to handle constructors parameters. Something like:

    class MockCls(val minValue: Int) {
      fun add(a: Int, b: Int) = minValue + a + b
    }
    
    mockkConstructor(MockCls::class)
    
    every { anyConstructed<MockCls>(10).add(1, 2) } returns 14
    
    assertEquals(14, MockCls(10).add(1, 2)) // note new object is created
    
    verify { anyConstructed<MockCls>(10).add(1, 2) } // success
    verify { anyConstructed<MockCls>(5).add(1, 2) } // fail
    

    For reference there is a question on SO about that.

    important 
    opened by Tryle 40
  • 1.12.5 fails to `every` certain java classes

    1.12.5 fails to `every` certain java classes

    I created a demo/minimal project here:

    https://gitlab.com/knyttl/mockkdemo/-/tree/main

    You can see the CI build with test failure here:

    https://gitlab.com/knyttl/mockkdemo/-/jobs/2782097977

    Feel free to change the build.gradle.kts mockk version to 1.12.4 which will test correctly.

    Expected Behavior

    The tests shouldn't fail.

    Current Behavior

    The test fails with:

    kotlin.reflect.jvm.internal.KotlinReflectionInternalError: Unresolved class: class org.elasticsearch.search.sort.SortOrder$1
    

    As you can see in the CI run mentioned above.

    Failure Information (for bugs)

    See CI run mentioned above.

    Steps to Reproduce

    See the source code mentioned above. Feel free to change the version to 1.12.4 which will build correctly.

    Context

    Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

    • MockK version: 1.12.5
    • Kotlin version: 1.7.10
    • JDK version: 17

    Minimal reproducible code (the gist of this issue)

    import io.mockk.every
    import io.mockk.mockk
    import org.elasticsearch.search.sort.SortOrder
    import org.junit.jupiter.api.Test
    
    class MockkDemo {
        @Test
        fun testMockk() {
            val repo = mockk<TestClass>()
            every { repo.getSchedules() } returns "Foo"
        }
    }
    
    class TestClass {
        fun getSchedules(sortOrder: SortOrder = SortOrder.ASC): String =
            sortOrder.toString()
    }
    
    opened by knyttl 37
  • Discussion: what are the (near future) plans for MockK?

    Discussion: what are the (near future) plans for MockK?

    This is not a MockK issue, but more a question/feedback to @oleksiyp (MockK's developer). I hope more people in the community feel this way. If so, please comment or give this issue a 👍. Or otherwise let me know what you think.

    First of all: thanks for MockK. I'm very happy with it. I hope it will continue to add value to the Kotlin community.

    Also, please note that I know you've commented on many issues already that your time is limited for good reasons. I think it's most important that you decide for yourself when to do what with your time. Please never change that.

    Now the feedback: I noticed that it's been quite quiet around MockK's developments. It's been more than half a year since the current latest release (v1.9.3) was released, while previous releases happened on about a monthly basis. In the mean time some developments have taken place: new issues and PRs were opened, addressed and closed for various things. You introduced a stale issue management bot to help you prioritise open issues. But it all went a little bit slower than before, which I understand considering that you only have 24 hours in a day to spend on whatever you decide is important. I like MockK a lot and therefore it's a pity that so little (visible) development happened since the last release. Also, the developments on the Kotlin language and official stdlib extensions, like coroutines, continue to move forward. I'm afraid MockK will lag behind at some point. And in general, I wonder what's going on with MockK and where this project is going. Therefore I want to ask you to clarify the following questions.

    What plans do you have for MockK? What do you need to keep actively developing on / maintaining MockK? Do you still want to be this project's lead developer? Do you need more time/motivation? Do you need maintainers? Do you need anything else?

    Please, see this issue as a central place where you give the MockK community feedback about what you want, what you need, or whatever ideas you have. Or maybe ask whatever questions you might have yourself.

    I'd love to help by working on MockK myself, but I think I neither have the time nor the required skills for it.

    What might be a bit of motivation is the upcoming KotlinConf: wouldn't it be awesome to have some new features/bug fixes done in time for the conference, so that it's clear that MockK is still a valuable contribution to the Kotlin community? Please let the community know what you need to make this happen. I think we all want the same? Please let the community know how we can get there.

    important 
    opened by erikhuizinga 33
  • Bug: IllegalStateException: Could not self-attach to current VM using external process on Open JDK 11.0.1

    Bug: IllegalStateException: Could not self-attach to current VM using external process on Open JDK 11.0.1

    We have main code in Java and tests in Kotlin. We build it and run the tests inside Docker container. All works locally but it does not work in our build environment. We have a Jenkins master running on AWS. It calls a slave node (also on AWS) to run the build. The build fails because of this library with the following error:

    [WARNING] Corrupted STDOUT by directly writing to native stream in forked JVM 1. See FAQ web page and the dump file /home/mbuilder/workspace/....dumpstream
    java.lang.ExceptionInInitializerError
    Caused by: java.lang.IllegalStateException: Could not self-attach to current VM using external process
    java.lang.NoClassDefFoundError: Could not initialize class io.mockk.impl.JvmMockKGateway
    

    The dumpstream file is attached 2019-02-12T15-01-39_092-jvmRun1.dumpstream(had to add .log extention for GitHub). Also, note that OurClassTest mentioned in the dumpstream is only 283 lines long, so there is no line 290 that is referenced there.

    bug 
    opened by Sam-Kruglov 32
  • Bug: Newer Objenesis 2.7 introduced in 1.9.3 is failing in Android Instrumented Tests

    Bug: Newer Objenesis 2.7 introduced in 1.9.3 is failing in Android Instrumented Tests

    • [x] I am running the latest version
    • [x] I checked the documentation and found no answer
    • [x] I checked to make sure that this issue has not already been filed

    Failure Information (for bugs)

    Building a test apk fails with MockK 1.9.3. No errors occur with MockK 1.9.2.

    Context

    • MockK version: 1.9.3
    • Kotlin version: 1.3.21
    • JDK version: openjdk version "1.8.0_191"
    • Type of test: android instrumented test

    This error occurs when building a test apk, not when running instrumented tests.

    Expected Behavior

    The build should be successful.

    Current Behavior

    The build fails:

    $ ./gradlew :examples:mockk:assembleAndroidTest
    D8: MethodHandle.invoke and MethodHandle.invokeExact are only supported starting with Android O (--min-api 26)
    
    > Task :examples:mockk:transformClassesWithDexBuilderForDebugAndroidTest FAILED
    com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.DexArchiveBuilderException: Failed to process /home/tmura/.gradle/caches/modules-2/files-2.1/org.objenesis/objenesis/3.0.1/11cfac598df9dc48bb9ed9357ed04212694b7808/objenesis-3.0.1.jar
            at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
            at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
            at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
            at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
            at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
            at java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:720)
            at com.android.ide.common.internal.WaitableExecutor.waitForTasksWithQuickFail(WaitableExecutor.java:146)
            at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.transform(DexArchiveBuilderTransform.java:420)
            at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:239)
            at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:235)
            at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:102)
            at com.android.build.gradle.internal.pipeline.TransformTask.transform(TransformTask.java:230)
            at sun.reflect.GeneratedMethodAccessor172.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
            at org.gradle.api.internal.project.taskfactory.IncrementalTaskAction.doExecute(IncrementalTaskAction.java:50)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:39)
            at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:26)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:131)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
            at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:120)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:99)
            at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:77)
            at org.gradle.api.internal.tasks.execution.OutputDirectoryCreatingTaskExecuter.execute(OutputDirectoryCreatingTaskExecuter.java:51)
            at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:59)
            at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
            at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:59)
            at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:101)
            at org.gradle.api.internal.tasks.execution.FinalizeInputFilePropertiesTaskExecuter.execute(FinalizeInputFilePropertiesTaskExecuter.java:44)
            at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:91)
            at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:62)
            at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:59)
            at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
            at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
            at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.run(EventFiringTaskExecuter.java:51)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:301)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:293)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:175)
            at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
            at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31)
            at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:46)
            at org.gradle.execution.taskgraph.LocalTaskInfoExecutor.execute(LocalTaskInfoExecutor.java:42)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:277)
            at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareWorkItemExecutor.execute(DefaultTaskExecutionGraph.java:262)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:135)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:130)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.execute(DefaultTaskPlanExecutor.java:200)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.executeWithWork(DefaultTaskPlanExecutor.java:191)
            at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$ExecutorWorker.run(DefaultTaskPlanExecutor.java:130)
            at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
            at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
            at java.lang.Thread.run(Thread.java:748)
    Caused by: com.android.builder.dexing.DexArchiveBuilderException: Failed to process /home/tmura/.gradle/caches/modules-2/files-2.1/org.objenesis/objenesis/3.0.1/11cfac598df9dc48bb9ed9357ed04212694b7808/objenesis-3.0.1.jar
            at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.launchProcessing(DexArchiveBuilderTransform.java:909)
            at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.lambda$convertToDexArchive$6(DexArchiveBuilderTransform.java:834)
            at java.util.concurrent.ForkJoinTask$AdaptedCallable.exec(ForkJoinTask.java:1424)
            at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
            at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
            at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
            at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
    Caused by: com.android.builder.dexing.DexArchiveBuilderException: Error while dexing.
            at com.android.builder.dexing.D8DexArchiveBuilder.getExceptionToRethrow(D8DexArchiveBuilder.java:124)
            at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:101)
            at com.android.build.gradle.internal.transforms.DexArchiveBuilderTransform.launchProcessing(DexArchiveBuilderTransform.java:904)
            ... 6 more
    Caused by: com.android.tools.r8.CompilationFailedException: Compilation failed to complete
            at com.android.tools.r8.utils.ExceptionUtils.withCompilationHandler(ExceptionUtils.java:70)
            at com.android.tools.r8.utils.ExceptionUtils.withD8CompilationHandler(ExceptionUtils.java:43)
            at com.android.tools.r8.D8.run(D8.java:94)
            at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:99)
            ... 7 more
    Caused by: com.android.tools.r8.utils.AbortException: Error: MethodHandle.invoke and MethodHandle.invokeExact are only supported starting with Android O (--min-api 26)
            at com.android.tools.r8.utils.Reporter.failIfPendingErrors(Reporter.java:89)
            at com.android.tools.r8.utils.Reporter.fatalError(Reporter.java:60)
            at com.android.tools.r8.utils.ExceptionUtils.withCompilationHandler(ExceptionUtils.java:64)
            ... 10 more
    
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':examples:mockk:transformClassesWithDexBuilderForDebugAndroidTest'.
    > com.android.build.api.transform.TransformException: com.android.builder.dexing.DexArchiveBuilderException: com.android.builder.dexing.DexArchiveBuilderException: Failed to process /home/tmura/.gradle/caches/modules-2/files-2.1/org.objenesis/objenesis/3.0.1/11cfac598df9dc48bb9ed9357ed04212694b7808/objenesis-3.0.1.jar
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 14s
    47 actionable tasks: 47 executed
    

    Steps to reproduce

    1. Run git clone https://github.com/tmurakami/dexopener.git && cd dexopener
    2. Change mockk-android:1.9.2 near the end of the root build.gradle to mockk-android:1.9.3
    3. Run ./gradlew :examples:mockk:assembleAndroidTest

    The cause is that Objenesis 3.0.1 on which MockK 1.9.3 relies contains code using java.lang.invoke.MethodHandle that is not present in versions prior to Android 8.0. https://github.com/easymock/objenesis/blob/8f601c8ba1aa20bbc640e2c2bc48d55df52c489f/main/src/main/java/org/objenesis/instantiator/util/DefineClassHelper.java

    bug ait important 
    opened by tmurakami 30
  • Feature: memorizing checked calls and allow to verify no more interactions to make it similar to Mockito verifyNoMoreInteractions()

    Feature: memorizing checked calls and allow to verify no more interactions to make it similar to Mockito verifyNoMoreInteractions()

    I have read other issues related to the equivalent of Mockito's verifyNoMoreInteractions() (#6, #50) and I think there are still some use cases which current DSL does not fully cover.

    I have the following test:

    // There are interactions with mock2 before that like initialization,
    // which are not important for the test
    verifyOrder {
        mock1.firstCall()
        mock2.someCall()
        mock1.secondCall()
    }
    // There are interactions with mock1 afterwards 
    // but there are no more interactions with mock2
    

    How can I check that there were no more interactions with mock2?

    I could probably add the following:

    verifyAll {
        mock2.someCall()
    }
    

    but it doesn't work when there were calls to mock2 before someCall() (which are irrelevant for the current test, like some initialization calls etc.). Even in cases where it would work this leads to duplicate code, which quickly gets ugly when there are many calls or methods have many parameters etc.

    Would be nice if there was something like:

    verify { mock2 wasNot CalledAnymore }
    
    enhancement fixed 
    opened by lukaszkalnik 28
  • #152 support value classes

    #152 support value classes

    Update:

    any() and slot() now support value classes!

    Summary

    • Added new 'expect' functions for 'unboxing' a value class to get its internal type, and to 'wrap' an object instance within a value class.
    • refactored RecordingState matcher to account for value classes
    • refactored the SignatureValueGenerator jvm impl to recursively generate values for value classes

    resolves #152 resolves #791 resolves #683 resolves #847

    Fix (maybe?) #778?

    Notes:

    • nested value classes aren't supported #859
    • This PR increases code duplication that should be refactored #857

    This PR will hopefully provide some support for value classes #152

    WIP - just some failing tests at the moment (credit to @qoomon)

    ~This PR is blocked at the moment because the Kotlin language level is set to 1.4 - see #850~ MockK is now on language level 1.5 🎉

    opened by aSemy 25
  • Message from Assertk assertions is not printed when using withArg block.

    Message from Assertk assertions is not printed when using withArg block.

    Prerequisites

    Please answer the following questions for yourself before submitting an issue.

    • [x] I am running the latest version
    • [x] I checked the documentation and found no answer
    • [x] I checked to make sure that this issue has not already been filed

    Expected Behavior

    The message from AssertionFailedError (which is thrown by Assertk lib) should be printed when assertion is performed in withArg block.

    Current Behavior

    The message from AssertionFailedError (which is thrown by Assertk lib) exception is not printed when the checking is performed in withArg block.

    Context

    Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

    • MockK version: 1.11.0
    • OS: macOS Big Sur
    • Kotlin version: 1.5
    • JDK version: 11
    • JUnit version: 5
    • Type of test: unit test

    Minimal reproducible code (the gist of this issue)

    // -----------------------[ GRADLE DEFINITIONS ] -----------------------
    
    project.ext.versions = [
      junit                : '5.7.2',
      assertk           : '0.24',
      mockk            : '1.11.0'
    ]
    
    dependencies {
      testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: versions.junit
      testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: versions.junit
      testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: versions.junit
      testImplementation group: 'com.willowtreeapps.assertk', name: 'assertk-jvm', version: versions.assertk
      testImplementation group: 'io.mockk', name: 'mockk', version: versions.mockk
    }
    // -----------------------[ YOUR CODE STARTS HERE ] -----------------------
    package some.example.com
    
    import io.mockk.every
    import io.mockk.mockk
    import org.apache.kafka.common.KafkaFuture
    import kotlin.test.Test
    
    class SomeExampleTest {
    
        val orderRepository: OrderRepository = mockk()
        val orderService: OrderService = OrderService(orderRepository)
    
        @Test
        fun test() {
           // given
           thereIsOrder(anOrder())
    
          // when
          orderService.pay(anOrderPayment())
    
          // then
          wasSaved(anOrder())
        }
        
        fun wasSaved(order: Order, times: Int = 1) {
          verify(exactly = times) {
             orderRepository.save(withArg{ equalsTo(order) })
          }
        }
        
        private fun MockKAssertScope.equalsTo(order: Order) {
                assertThat(this.actual as Order)
               .hasCommandId(order.commandId)
               .hasOrderId(order.orderId)
               // and so on     
      }
    
        // walk around
        private fun MockKAssertScope.equalsToAndLog(order: Order) {
           try {
                assertThat(this.actual as Order)
               .hasCommandId(order.commandId)
               .hasOrderId(order.orderId)
               // and so on
           } catch (t: Throwable) {
               logger.error(t) {}
               throw t
           }
      }
    }
    // -----------------------[ YOUR CODE ENDS HERE ] -----------------------
    

    I found that exception is catched here, and the stacktrace is not logged.

    package io.mockk
    
    data class FunctionMatcher<in T : Any>(
        val matchingFunc: (T) -> Boolean,
        override val argumentType: KClass<*>
    ) : Matcher<T>, TypedMatcher, EquivalentMatcher {
        override fun equivalent(): Matcher<Any> = ConstantMatcher(true)
    
        override fun match(arg: T?): Boolean {
            return if(arg == null) {
                false
            } else {
                try {
                    matchingFunc(arg)
                } catch (a: AssertionError) {
                    false
                }
            }
        }
    
        override fun toString(): String = "matcher<${argumentType.simpleName}>()"
    }
    
    opened by CamilYed 21
  • Broken mocking of sealed classes after upgrading to 1.13.2

    Broken mocking of sealed classes after upgrading to 1.13.2

    Prerequisites

    After upgrading mockk dependency from 1.13.1 to 1.13.2 many tests started to fail in our project. It seems to be related to https://github.com/mockk/mockk/pull/916.

    The problem is related to sealed classes or interfaces with child objects or data classes.

    To make it easier to understand, I've prepared reproduction project: https://github.com/vudzkostek/MockKReproduce

    There are two different crashes in my sample project, both related to version 1.13.2. When downgraded to 1.13.1 everything passes.

    I am not entirely sure if these failing tests are intended result of https://github.com/mockk/mockk/pull/916 or real issue that should be fixed in next release.

    Stack traces

    // -----------------------[ YOUR STACK STARTS HERE ] -----------------------
    Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
    io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock
    // -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------
    
    // -----------------------[ YOUR STACK STARTS HERE ] -----------------------
    java.lang.NullPointerException
    	at com.kosta.mockkreproduction.OtherSealedClass$Subtype1.hashCode(OtherSealedClass.kt)
    // -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------
    
    opened by vudzkostek 0
  • Test fails on CI server when run in parallel

    Test fails on CI server when run in parallel

    When I have a failing test, I would always see some unrelated test file printing stack trace mentioned below. It seems to be happening only on CI server, but I can't reproduce it on local macbook. If I disable parallel test runs, everything works as expected. Can someone elaborate on how to approach every/verify {} block were run several times. Recorded calls count differ between runs error?

    Expected Behavior

    I expect my tests to run parallel no matter the core count and machine running them.

    Current Behavior

    Works on my machine, but not on CI server.

    Steps to Reproduce

    Unfortunately, I can't reproduce this issue without providing my full project.

    Context

    Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

    • MockK version: 1.13.1
    • OS: Linux
    • Kotlin version: 1.7.20
    • JDK version: JDK19
    • JUnit version: junit:junit:4.13.2
    • Type of test: unit test

    Stack trace

    com.app.uicommon.login.twoFactor.twoFactorBackupCode.TwoFactorBackupViewModelTest > SpecInstantiationException FAILED
    
        java.lang.reflect.InvocationTargetException
    
            at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:79)
    
            at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    
            at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:484)
    
            at kotlin.reflect.jvm.internal.calls.CallerImpl$Constructor.call(CallerImpl.kt:41)
    
            at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
    
            at io.kotest.engine.spec.InstantiateSpecKt.javaReflectNewInstance(instantiateSpec.kt:51)
    
            at io.kotest.engine.spec.InstantiateSpecKt.createAndInitializeSpec(instantiateSpec.kt:30)
    
            at io.kotest.engine.spec.SpecRunner.createInstance-gIAlu-s(SpecRunner.kt:54)
    
            at io.kotest.engine.spec.runners.InstancePerLeafSpecRunner.executeInCleanSpec-gIAlu-s(InstancePerLeafSpecRunner.kt:87)
    
            at io.kotest.engine.spec.runners.InstancePerLeafSpecRunner.execute-gIAlu-s(InstancePerLeafSpecRunner.kt:81)
    
            at io.kotest.engine.spec.runners.InstancePerLeafSpecRunner$execute$1.invokeSuspend(InstancePerLeafSpecRunner.kt)
    
            at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    
            at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:33)
    
            at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102)
    
            at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
    
            at kotlinx.coroutines.UndispatchedCoroutine.afterResume(CoroutineContext.kt:233)
    
            at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102)
    
            at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
    
            at kotlinx.coroutines.UndispatchedCoroutine.afterResume(CoroutineContext.kt:233)
    
            at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:102)
    
            at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
    
            at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    
            at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
    
            at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
    
            at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    
            at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    
            at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
    
            at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    
            at io.kotest.common.RunBlockingKt.runBlocking(runBlocking.kt:3)
    
            at io.kotest.engine.TestEngineLauncher.launch(TestEngineLauncher.kt:194)
    
            at io.kotest.runner.junit.platform.KotestJunitPlatformTestEngine.execute(KotestJunitPlatformTestEngine.kt:82)
    
            at io.kotest.runner.junit.platform.KotestJunitPlatformTestEngine.execute(KotestJunitPlatformTestEngine.kt:46)
    
            at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
    
            at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    
            at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    
            at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    
            at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    
            at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    
            at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
    
            at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
    
            at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
    
            at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    
            at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    
            at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    
            at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
    
            at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    
            at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    
            at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    
            at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    
            at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    
            at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    
            at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
    
            at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
    
            at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    
            at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    
            at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    
            at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    
            at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
    
            at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
    
            at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    
            at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
    
    
    
            Caused by:
    
            io.mockk.MockKException: every/verify {} block were run several times. Recorded calls count differ between runs
    
            Round 1: StringProvider(#184).getString(-1851205945, [])
    
            Round 2: StringProvider(#191).getString(2132017409, []), StringProvider(#191).getString(2132017900, []), StringProvider(#191).getString(2132017901, []), StringProvider(#184).getString(1236631704, [])
    
                at app//io.mockk.impl.recording.SignatureMatcherDetector.detect$checkAllSameNumberOfCalls(SignatureMatcherDetector.kt:25)
    
                at app//io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:86)
    
                at app//io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
    
                at app//io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
    
                at app//io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
    
                at app//io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:63)
    
                at app//io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    
                at app//io.mockk.MockKDsl.internalCoEvery(API.kt:99)
    
                at app//io.mockk.MockKKt.coEvery(MockK.kt:116)
    
                at app//com.app.uicommon.login.twoFactor.twoFactorBackupCode.TwoFactorBackupViewModelTest.<init>(TwoFactorBackupViewModelTest.kt:25)
    

    Minimal reproducible code (the gist of this issue)

     val stringProvider = mockk<StringProvider>(relaxed = true)
      every { stringProvider.getString(id = any()) } returns "error"
    
    opened by smworks 0
  • Spyk'ed object can't be  unmocked which leads to OutOfMemoryError

    Spyk'ed object can't be unmocked which leads to OutOfMemoryError

    Expected Behavior

    unmock(spyk()) -- works No java.lang.OutOfMemoryError: Java heap space error occurred.

    Current Behavior

    java.lang.OutOfMemoryError: Java heap space occurs

    unmock(spyk()) -- does not unmock spyk'ed object

    Failure Information (for bugs)

    Context

    We have a lot of SpringBoot tests . We annotated @Lazy bean with @SpykBean in our TestCaseBase class And sometimes new spring context created and bean get spyked again and it leads to OutOfMemoryError because spiked object can't be unmocked/unspyked

    • MockK version: implementation("io.mockk:mockk:1.13.3")

    • OS: Darwin 21.6.0 Darwin Kernel Version 21.6.0: Thu Sep 29 20:13:56 PDT 2022; root:xnu-8020.240.7~1/RELEASE_ARM64_T6000 arm64

    • Kotlin version: 1.7.21

    • JDK version: openjdk 11.0.16.1 2022-08-12 OpenJDK Runtime Environment Homebrew (build 11.0.16.1+0) OpenJDK 64-Bit Server VM Homebrew (build 11.0.16.1+0, mixed mode)

    • Type of test: unit test

    Minimal reproducible code (the gist of this issue)

    // -----------------------[ GRADLE DEFINITIONS ] -----------------------
    dependencies {
        testImplementation(kotlin("test"))
        implementation("io.mockk:mockk:1.13.3")
    }
    
    tasks.test {
        useJUnitPlatform()
    }
    
    tasks.withType<KotlinCompile> {
        kotlinOptions.jvmTarget = "1.8"
    }
    
    application {
        mainClass.set("MainKt")
    }
    // -----------------------[ YOUR CODE STARTS HERE ] -----------------------
    
    
    fun main(args: Array<String>) {
        (0..1000).forEach {
            val spyk = spyk(LazySpringBeanWhichHoldsReferenceForBeanFactory(ByteArray(10 * 1024 * 1024)))
            every { spyk.doSmth() } returns "Wow"
            spyk.doSmth();
            clearMocks(spyk)
            unmockkObject(spyk)
        }
    }
    
    class LazySpringBeanWhichHoldsReferenceForBeanFactory(val beanFactory: ByteArray){
        fun doSmth():String{
                return "Smth"
        }
    }
    
    opened by bakomchik 1
  • mockkStatic doesn't work with anyConstructed(), constructedWith() see also (https://github.com/mockk/mockk/issues/874)

    mockkStatic doesn't work with anyConstructed(), constructedWith() see also (https://github.com/mockk/mockk/issues/874)

    Just be aware about usual MockK support pattern. Tickets are checked from time to time, replied, discussed, labeled, e.t.c. But real fixes are applied in a month-two month period in a bunch. If you think this is unacceptable, go on, join the project, change the world.

    Please remove sections wisely

    Below information is actually needed to make all the process of fixing faster. Choose main points. Don't blindly follow this as a set of rules. Don't waste much time. Usually, the main thing is to have a good reproducible minimal code.

    Prerequisites

    Please answer the following questions for yourself before submitting an issue.

    • [ ] I am running the latest version
    • [ ] I checked the documentation and found no answer
    • [ ] I checked to make sure that this issue has not already been filed

    Expected Behavior

    mockkStatic("path")/mockkStatic(Obj:: extensionFunc) tried both options every { anyConstucted()/constructedWith().extensionFunc() } should mockk the extension function and return provided value

    Current Behavior

    MockkStatic doesn't work. The real code inside the extension function is executed and the provided value is not returned.

    Failure Information (for bugs)

    1. both of anyConstructed and constructedWith with mockkStatic("path") and mockkStatic(Obj:: extensionFunc) with all possible combinations fail
    2. every {anyConstructed()/constructedWith().extensionFunc()} doesn't work
    3. every { mockObject.extensionFunc() } works as expected
    4. every { anyConstructed()/constructedWith().notExtensionFunc() } works as expected

    Context

    Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

    • MockK version: 1.13.3
    • OS: MAC OS
    • Kotlin version: kotlin-stdlib-jdk7:1.3.11
    • JDK version: JavaVersion.VERSION_1_8
    • JUnit version: JUnit 4
    • Type of test: unit test

    Please include any relevant log snippets or files here.

    Minimal reproducible code (the gist of this issue)

    // -----------------------[ GRADLE DEFINITIONS ] -----------------------
    dependencies {
        testCompile group: 'org.apache.kafka', name: 'kafka_2.12', version: '1.1.0'
    }
    // -----------------------[ YOUR CODE STARTS HERE ] -----------------------
    package io.mockk.gh
    
    import io.mockk.every
    import io.mockk.mockk
    import org.apache.kafka.common.KafkaFuture
    import kotlin.test.Test
    
    class Issue69Test {
    
    //The same code works correctly when applyBundle() is not extension but function inside MyFragment
     @Test
        fun test() {
            val fragmentMock: MyFragment = mockk()
    
            mockkStatic("extensionPath")
            mockkConstructor(MyFragment::class)
    
            every { anyConstructed<MyFragment>().applyBundle(params) } returns fragmentMock
    
            myClass.getFragment()
    
            verify { anyConstructed<MyFragment>().applyBundle(params) }
    
        }
    
    }
    // -----------------------[ YOUR CODE ENDS HERE ] -----------------------
    
    opened by l3von 0
  • Exception occurs using nested mocks (`Failed matching mocking signature for`)

    Exception occurs using nested mocks (`Failed matching mocking signature for`)

    • [x] I am running the latest version
    • [x] I checked the documentation and found no answer
    • [x] I checked to make sure that this issue has not already been filed

    Expected Behavior

    No exception occurs

    Current Behavior

    Exception occurs.

    Failure Information (for bugs)

    This seems to be a bug, because when using version 1.13.1, the problem does not occur. It began occurring in version 1.13.2, and it keeps occurring in 1.13.3.

    Steps to Reproduce

    See snippet below. To reproduce, simply run SomeTest#should test.

    Context

    • MockK version: 1.13.3
    • OS: MacOS 13.1
    • Kotlin version: 1.6.21
    • JDK version: 19.0.1 (arm)
    • JUnit version: 5.8.2
    • Type of test: unit test

    Stack trace

    // -----------------------[ YOUR STACK STARTS HERE ] -----------------------
    io.mockk.MockKException: Failed matching mocking signature for
    
    left matchers: [any()]
    
    	at io.mockk.impl.recording.SignatureMatcherDetector.detect(SignatureMatcherDetector.kt:99)
    	at io.mockk.impl.recording.states.RecordingState.signMatchers(RecordingState.kt:39)
    	at io.mockk.impl.recording.states.RecordingState.round(RecordingState.kt:31)
    	at io.mockk.impl.recording.CommonCallRecorder.round(CommonCallRecorder.kt:50)
    	at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:63)
    	at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
    	at io.mockk.MockKDsl.internalEvery(API.kt:94)
    	at io.mockk.MockKKt.every(MockK.kt:143)
    	at com.github.SomeTest$should test$1.invokeSuspend(SomeTest.kt:62)
    	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:279)
    	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
    	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
    	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    	at com.github.SomeTest.should test(SomeTest.kt:57)
    	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
    	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
    	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
    	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
    	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
    	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
    	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
    	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
    // -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------
    

    Minimal reproducible code (the gist of this issue)

    // -----------------------[ YOUR CODE STARTS HERE ] -----------------------
    package com.github
    
    import io.mockk.every
    import io.mockk.mockk
    import kotlinx.coroutines.runBlocking
    import org.junit.jupiter.api.Test
    
    data class ClassA(
        val sealedClassA: SealedClassA,
    )
    
    sealed class SealedClassA
    
    data class SealedClassA1(
        val sealedClassB: SealedClassB,
    ) : SealedClassA()
    
    /**
     * some interface
     */
    interface Interface1 {
        fun <T> accept(visitor: Interface2<T>): T
    }
    
    /**
     * another sealed class
     */
    sealed class SealedClassB : Interface1
    
    data class SealedClassB1(
        val attribute: String,
    ) : SealedClassB() {
        override fun <T> accept(visitor: Interface2<T>) = visitor.visit(this)
    }
    
    data class SealedClassB2(
        val attribute: String,
    ) : SealedClassB() {
        override fun <T> accept(visitor: Interface2<T>) = visitor.visit(this)
    }
    
    /**
     * another interface
     */
    interface Interface2<T> {
        fun visit(sealedClassB1: SealedClassB1): T
        fun visit(sealedClassB2: SealedClassB2): T
    }
    
    class Interface2Impl : Interface2<String> {
        override fun visit(sealedClassB1: SealedClassB1) = ""
        override fun visit(sealedClassB2: SealedClassB2) = ""
    }
    
    class SomeTest {
        @Test
        fun `should test`() = runBlocking<Unit> {
            val x = mockk<ClassA>(relaxed = true)
    
            every { x.sealedClassA } returns mockk<SealedClassA1> {
                every { sealedClassB } returns mockk {
                    every { accept(any<Interface2Impl>()) } returns ""
                }
            }
        }
    }
    // -----------------------[ YOUR CODE ENDS HERE ] -----------------------
    
    opened by pedro-carneiro 0
Releases(1.13.3)
  • 1.13.3(Nov 29, 2022)

    What's Changed

    • Add Awaits extensions similar to Runs to await suspend functions until cancelled by @SimonMarquis in https://github.com/mockk/mockk/pull/927
    • Upgrade Kotlin to stable 1.7.20 in GitHub workflow by @SimonMarquis in https://github.com/mockk/mockk/pull/940
    • Add missing test annotation to LambdaTest by @bossm0n5t3r in https://github.com/mockk/mockk/pull/946
    • Fix verifier logic for slots and different matchers by @m-burst in https://github.com/mockk/mockk/pull/951
    • Fix InstantiationError when using any() where a sealed type is expected by @cliffred in https://github.com/mockk/mockk/pull/939
    • Adding throwsMany exception by @daniel-dios in https://github.com/mockk/mockk/pull/955
    • Add more doc comments with samples by @NotWoods in https://github.com/mockk/mockk/pull/958
    • added basic jitpack config by @hduerkop in https://github.com/mockk/mockk/pull/962
    • add kotlin 1.8-Beta to the test matrix by @aSemy in https://github.com/mockk/mockk/pull/974
    • bump bytebuddy and objenesis by @aSemy in https://github.com/mockk/mockk/pull/975
    • Update README.md to include note about 2-year-old 'known issue' for spy and suspend function by @iainism in https://github.com/mockk/mockk/pull/979

    New Contributors

    • @SimonMarquis made their first contribution in https://github.com/mockk/mockk/pull/927
    • @bossm0n5t3r made their first contribution in https://github.com/mockk/mockk/pull/946
    • @m-burst made their first contribution in https://github.com/mockk/mockk/pull/951
    • @cliffred made their first contribution in https://github.com/mockk/mockk/pull/939
    • @daniel-dios made their first contribution in https://github.com/mockk/mockk/pull/955
    • @NotWoods made their first contribution in https://github.com/mockk/mockk/pull/958

    Full Changelog: https://github.com/mockk/mockk/compare/1.13.2...1.13.3

    Source code(tar.gz)
    Source code(zip)
  • 1.13.2(Sep 28, 2022)

    What's Changed

    • update dependencies in readme to reflect new multiplatform structure by @aSemy in https://github.com/mockk/mockk/pull/926
    • Properly handle sealed classes with Kotlin 1.7 and JDK 17 by @stuebingerb in https://github.com/mockk/mockk/pull/916
    • add jdk 19 to workflow test matrix by @aSemy in https://github.com/mockk/mockk/pull/933

    New Contributors

    • @stuebingerb made their first contribution in https://github.com/mockk/mockk/pull/916

    Full Changelog: https://github.com/mockk/mockk/compare/1.13.1...1.13.2

    Source code(tar.gz)
    Source code(zip)
  • 1.13.1(Sep 23, 2022)

    New major release, mainly because the dependency to be included in gradle/maven files has changed from io.mockk:mockk to io.mockk:mockk-<platform>, where platform is either jvm or android.

    What's Changed

    • value class check - catch KotlinReflectionInternalError by @aSemy in https://github.com/mockk/mockk/pull/922

    Full Changelog: https://github.com/mockk/mockk/compare/v1.12.8...1.13.1

    Source code(tar.gz)
    Source code(zip)
  • v1.12.8(Sep 15, 2022)

    Big thanks to @aSemy, @qoomon and @kubode for investigating and fixing the bugs introduced in v1.12.7 and further improving the library!

    What's Changed

    • fix: handle isValue exceptions by @qoomon in https://github.com/mockk/mockk/pull/890
    • Fix Android Instrumentation dispatcher.jar inclusion by @aSemy in https://github.com/mockk/mockk/pull/899
    • Standardise JVM target to be 1.8 by @aSemy in https://github.com/mockk/mockk/pull/900
    • introduce Kotlinx Benchmark tests (copied from #763) by @aSemy in https://github.com/mockk/mockk/pull/904
    • try reverting Android minSdk to 21 by @aSemy in https://github.com/mockk/mockk/pull/901
    • expose more mockk projects as API dependencies by @aSemy in https://github.com/mockk/mockk/pull/905
    • make Java source code target jvm 8 by @aSemy in https://github.com/mockk/mockk/pull/907
    • Fix an issue that Android Instrumentation Test fails by @kubode in https://github.com/mockk/mockk/pull/895
    • use the official Gradle GHA by @aSemy in https://github.com/mockk/mockk/pull/914
    • De-duplicate ValueClassSupport by @aSemy in https://github.com/mockk/mockk/pull/913
    • add 1.7.20-RC to test matrix by @aSemy in https://github.com/mockk/mockk/pull/918

    Full Changelog: https://github.com/mockk/mockk/compare/1.12.7...v1.12.8

    Source code(tar.gz)
    Source code(zip)
  • 1.12.7(Aug 23, 2022)

    What's Changed

    • Update android-sdk-detector.settings.gradle.kts by @aSemy in https://github.com/mockk/mockk/pull/886
    • only sign if the signing properties are present by @aSemy in https://github.com/mockk/mockk/pull/885
    • Fix an issue that Android libraries was not published by @kubode in https://github.com/mockk/mockk/pull/887

    New Contributors

    • @kubode made their first contribution in https://github.com/mockk/mockk/pull/887

    Full Changelog: https://github.com/mockk/mockk/compare/1.12.6...1.12.7

    Source code(tar.gz)
    Source code(zip)
  • 1.12.6(Aug 22, 2022)

    Broken release, don't use this

    If you are upgrading from a previous version, please upgrade directly to 1.12.7 or higher. Sorry for the inconvenience.

    What's Changed

    • Dependency updates, JDK17 v2 by @aSemy in https://github.com/mockk/mockk/pull/863
    • Dependency updates, JDK17 by @hduerkop in https://github.com/mockk/mockk/pull/829
    • Fix unmockkAll to work if constructor was mocked multiple times by @Chrostoq in https://github.com/mockk/mockk/pull/870
    • fix: fix value class field determination by @qoomon in https://github.com/mockk/mockk/pull/872
    • #854 update projects to use new Kotlin Multiplatform Gradle plugin by @aSemy in https://github.com/mockk/mockk/pull/855

    New Contributors

    • @hduerkop made their first contribution in https://github.com/mockk/mockk/pull/829
    • @Chrostoq made their first contribution in https://github.com/mockk/mockk/pull/870

    Full Changelog: https://github.com/mockk/mockk/compare/1.12.5...1.12.6

    Source code(tar.gz)
    Source code(zip)
  • 1.12.5(Jul 27, 2022)

    Thanks a lot @aSemy and @qoomon for the big effort to add value class support!

    What's Changed

    • Better detection of unnecessary stubbing by @PHaroZ in https://github.com/mockk/mockk/pull/825
    • Build logic improvements by @c00ler in https://github.com/mockk/mockk/pull/840
    • remove invalid 'flowRoot' from SVGs, resize documents to contents by @aSemy in https://github.com/mockk/mockk/pull/852
    • bump kotlin 1.7.10, and language level to 1.5 by @aSemy in https://github.com/mockk/mockk/pull/850
    • Update 'all tests' GitHub action, enable Gradle Build Cache by @aSemy in https://github.com/mockk/mockk/pull/862
    • #832 Add tests for sealed classes by @aSemy in https://github.com/mockk/mockk/pull/861
    • #152 support value classes by @aSemy in https://github.com/mockk/mockk/pull/849

    New Contributors

    • @PHaroZ made their first contribution in https://github.com/mockk/mockk/pull/825
    • @c00ler made their first contribution in https://github.com/mockk/mockk/pull/840

    Full Changelog: https://github.com/mockk/mockk/compare/1.12.4...1.12.5

    Source code(tar.gz)
    Source code(zip)
  • 1.12.4(May 11, 2022)

    • Add a Junit 4 rule, thanks @jonapoul
    • Recognize atLeast = 0, thanks @uyw4687
    • Revert the latest change about logging messages in withArg calls as it seems community usage was being impacted by the change, thanks @romrell4 for the revert
    • Added the @ConfirmVerification extension, fixes #215, #334 and related issues
    • Add languageVersion = 1.4 and the kotlin binary compatibility validator plugin
    • Upgrade Objenesis to 3.2
    Source code(tar.gz)
    Source code(zip)
  • 1.12.3(Feb 28, 2022)

    • Fixed #707 via #776, thanks @romrell4
    • Fixed #754 fia #782, thanks @hoisie
    • Fixed #425 via #785, thanks @npars
    • Added Quarkus support, thanks @glefloch
    • Updated logback to 1.2.10, thanks @Neustradamus
    • Converted some more build.gradle files to kotlin and bumped some JDK and kotlin versions
    Source code(tar.gz)
    Source code(zip)
  • 1.12.2(Dec 30, 2021)

    • Add andThenJust, thanks @NWuensche
    • Upgraded gradle and several dependencies versions, including the logback dependency that was vulnerable to https://cve.report/CVE-2021-42550, thanks @SampathKumarAmex and @usulkies (and @jbg for spotting the CVE vulnerability)
    • Converted some more build.gradle files to Kotlin, thanks @geekiyer
    Source code(tar.gz)
    Source code(zip)
  • 1.12.1(Nov 17, 2021)

    • Fixed #565, thanks @AlexKrupa
    • Reorganized tests to reflect the real feature they test rather than the number of the GitHub issue, thanks @drazen04, @fejd, @polarene
    • Converted most of the build.gradle files to kotlin, thanks @geekiyer, @vasanthdharmaraj, @fejd, @DeKaN
    • Fixed a wrong behavior with unmockkAll inside the MockKExtension, thanks @gmazzo
    • Improved support for verification stack traces, thanks @kkurczewski
    Source code(tar.gz)
    Source code(zip)
  • v1.12.0(Jul 1, 2021)

    • Support for mocking value classes (#633, thanks @qoomon)
    • Support for setting a custom anyValueGenerator (fixes #642, thanks @hrach)
    • Support for relaxed mocking when mocking suspend functions (#640, thanks @hrach)
    • Fixed a bug with @InjectMocks not supporting constructor argument defaults (#646, thanks @vladkanash)
    • Reorganized some tests (thanks @drazen04 and @Endhuine)
    • Bumped bytebuddy version (thanks @christophsturm)
    Source code(tar.gz)
    Source code(zip)
  • 1.11.0(Mar 17, 2021)

  • 1.10.6(Feb 13, 2021)

  • 1.10.5(Jan 14, 2021)

    Rolled back to Kotlin v1.3.72 to fix backwards compatibility issues; looks like we upgraded to Kotlin 1.4 too soon, will likely upgrade again when the adoption of Kotlin 1.4 is higher.

    Source code(tar.gz)
    Source code(zip)
  • 1.10.4(Dec 29, 2020)

  • 1.10.3-jdk8(Dec 1, 2020)

  • 1.10.3(Nov 30, 2020)

    • upgrade to 1.4.20
    • issue #352 prevent slots from being used when verifying multiple calls
    • issue #510 changed the answers for collections to return a new instance every time
    • issue #315: Allow to combine @SpyK with @InjectMockKs
    • PR #518 mockkStatic hard reference support
    Source code(tar.gz)
    Source code(zip)
  • 1.10.0(Apr 19, 2020)

    • fix of build scripts (big effort to restore build after Gradle upgrade)
    • gradle 6.3, kotlin 1.3.61, byte buddy 1.10.9, coroutines 1.3.3, objenesis 3.1/2.6, dokka 0.10.1
    • JDK 13 / 14 runnable
    • make stack traces in verify messages optional #427
    Source code(tar.gz)
    Source code(zip)
  • 1.9.3.kotlin12(Mar 24, 2019)

  • 1.9.3(Mar 24, 2019)

  • 1.9.2.kotlin12(Mar 10, 2019)

  • 1.9.2(Mar 10, 2019)

  • 1.9.1.kotlin12(Feb 10, 2019)

    • Feature: Nested mocking objects #244
    • SLF4J warnings #243
    • autohinting may fail unexpectedly when run in mixed mode, suppressing the useful message that a hint might be necessary in the test fixture #240
    • mockk throws ClassNotFoundException: io.mockk.proxy.jvm.dispatcher.JvmMockKDispatcher when run with Spek2 #239
    • Bug: clearAllMocks doesn't clear static mock of java.lang.System #234
    • @MockK(relaxed = true) doesn't behave same way as @RelaxedMockK for Jupiter method parameters #232
    • mockkClass() should have a relaxUnitFun argument #227
    • Bug: Mocking annotation causes MockkException #226
    • Bug: Mocking varargs on 1.9 #224
    • Bug: mock that return set of Mocks fails #221
    • Feature: make clearMocks without arguments not possible #217
    • Feature: returns that creating a new mock and setting behavior #201
    • Bug: cannot verify mock method with abstract argument using any() #131
    Source code(tar.gz)
    Source code(zip)
  • 1.9.1(Feb 10, 2019)

    • Feature: Nested mocking objects #244
    • SLF4J warnings #243
    • autohinting may fail unexpectedly when run in mixed mode, suppressing the useful message that a hint might be necessary in the test fixture #240
    • mockk throws ClassNotFoundException: io.mockk.proxy.jvm.dispatcher.JvmMockKDispatcher when run with Spek2 #239
    • Bug: clearAllMocks doesn't clear static mock of java.lang.System #234
    • @MockK(relaxed = true) doesn't behave same way as @RelaxedMockK for Jupiter method parameters #232
    • mockkClass() should have a relaxUnitFun argument #227
    • Bug: Mocking annotation causes MockkException #226
    • Bug: Mocking varargs on 1.9 #224
    • Bug: mock that return set of Mocks fails #221
    • Feature: make clearMocks without arguments not possible #217
    • Feature: returns that creating a new mock and setting behavior #201
    • Bug: cannot verify mock method with abstract argument using any() #131
    Source code(tar.gz)
    Source code(zip)
  • v1.9.kotlin12(Jan 4, 2019)

  • 1.9(Jan 4, 2019)

  • 1.8.13.kotlin13(Nov 16, 2018)

  • 1.8.13(Nov 16, 2018)

  • 1.8.12.kotlin13(Nov 4, 2018)

Owner
MockK
Pure Kotlin mocking framework
MockK
Easy Response Mocking for Retrofit using annotations

Response Mocking for Retrofit using annotations. Assume Provides safe and easy way to mock API responses for retrofit-okhttp3.

Aniket Bhoite 25 Nov 16, 2021
Most popular Mocking framework for unit tests written in Java

Most popular mocking framework for Java Current version is 3.x Still on Mockito 1.x? See what's new in Mockito 2! Mockito 3 does not introduce any bre

mockito 13.6k Jan 4, 2023
A micro mocking framework for KMP

Micro-Mock A micro Kotlin/Multiplatform Kotlin Symbol Processor that generates Mocks & Fakes. Limitations: Mocking only applies to interfaces Faking o

null 101 Jan 3, 2023
Selenium locators for Java/Kotlin that resemble the Testing Library (testing-library.com).

Selenium Testing Library Testing Library selectors available as Selenium locators for Kotlin/Java. Why? When I use Selenium, I don't want to depend on

Luís Soares 5 Dec 15, 2022
A multiplatform assertion library for Kotlin

Atrium is an open-source multiplatform assertion library for Kotlin with support for JVM, JS and Android. It is designed to support multiple APIs, dif

Robert Stoll 439 Dec 29, 2022
Strikt is an assertion library for Kotlin intended for use with a test runner such as JUnit, Minutest, Spek, or KotlinTest.

Strikt is an assertion library for Kotlin intended for use with a test runner such as JUnit, Minutest, Spek, or KotlinTest.

Rob Fletcher 447 Dec 26, 2022
A Kotlin Android library for heuristics evasion that prevents your code from being tested.

EvadeMe An Android library for heuristics evasion that prevents your code from being tested. User Instructions Add the maven repository to your projec

Chris Basinger 29 Dec 26, 2022
Kotlin wrapper for React Test Renderer, which can be used to unit test React components in a Kotlin/JS project.

Kotlin API for React Test Renderer Kotlin wrapper for React Test Renderer, which can be used to unit test React components in a Kotlin/JS project. How

Xavier Cho 7 Jun 8, 2022
Android library that allows you to run your acceptance tests written in Gherkin in your Android instrumentation tests.

Green Coffee Green Coffee is a library that allows you to run your acceptance tests written in Gherkin in your Android instrumentation tests using the

Mauricio Togneri 227 Nov 21, 2022
Linkester is an Android library that aims to help Android developers test their deep links implementation.

Linkester Linkester is an Android library that aims to help Android developers test their deep links implementation. The idea is to have a new launche

Ahmad Melegy 79 Dec 9, 2022
Jitpack Library Tester

jitpack-library-test Repository for testing build from jitpack.io Red : Failed Green : Success / Pass Colaborator Very open to anyone, I'll write your

Faisal Amir 7 Dec 10, 2022
Turbine is a small testing library for kotlinx.coroutines Flow.

A small testing library for kotlinx.coroutines Flow

Cash App 1.8k Jan 5, 2023
A library that makes it easier to write high quality automated acceptance tests

Getting started with Serenity and Cucumber Serenity BDD is a library that makes it easier to write high quality automated acceptance tests, with power

ricardo larrahondo 1 Oct 20, 2021
An experimental library for dealing with legacy code

All Super experimental! no guarantees to the public API surface. At the moment, this project is the outcome of the limitations of my search skills. Bu

Ragunath Jawahar 5 Jan 18, 2022
Library to simplify and speed up the creation and work with adapters with payload.

Novalles Library to simplify and speed up the creation and work with adapters with payload. How to use Annotate your UI model with UIModel Annotation.

Бырна Алексей 3 Oct 11, 2022
Portable validations for Kotlin

Portable validations for Kotlin ✅ Type-safe DSL ?? Multi-platform support (JVM, JS) ?? Zero dependencies Installation For multiplatform projects: kotl

null 509 Dec 18, 2022
Powerful, elegant and flexible test framework for Kotlin with additional assertions, property testing and data driven testing

Kotest is a flexible and comprehensive testing tool for Kotlin with multiplatform support. To learn more about Kotest, visit kotest.io or see our quic

Kotest 3.8k Jan 3, 2023
Fixtures for Kotlin providing generated values for unit testing

A tool to generate well-defined, but essentially random, input following the idea of constrained non-determinism.

Appmattus Limited 191 Dec 21, 2022
Lightweight service for creating standalone mock, written in pure Kotlin with Netty container.

MockService The lightweight service for creating a standalone mock, written in pure Kotlin with Netty container. The service allows getting config fil

null 2 Oct 28, 2021