A micro mocking framework for KMP

Related tags

Testing Micro-Mock
Overview

Micro-Mock

A micro Kotlin/Multiplatform Kotlin Symbol Processor that generates Mocks & Fakes.

Limitations:

  • Mocking only applies to interfaces

  • Faking only applies to concrete trees

Warning

Micro-Mock is in Beta!

  • It depends on weird Kotlin/Native behaviour and may break with new Kotlin versions (in which case we’ll try to update it as soon as possible).

  • While it is being used in some of our production unit tests, it has not been widely tested, and may fail on your setup. In which case, please post an issue…​ or a pull request if you feel like contributing ;)

Usage

Mocks

Caution
Only interfaces can be mocked!

Requesting generation

You can declare that a class needs a specific mocked interface by using the @UsesMocks annotation.

@UsesMocks(Database::class, API::class)
class MyTests {
}

Once a type appears in @UsesMocks, the processor will generate a mock class for it.

Defining behaviour

To manipulate a mocked type, you need a Mocker. You can then create mocked types and define their behaviour:

@UsesMocks(Database::class, API::class)
class MyTests {
    @Test fun myUnitTest() {
        val mocker = Mocker()
        val db = MockDatabase(mocker)
        val api = MockAPI(mocker)

        mocker.on { db.open(isAny()) } returns Unit //(1)
        mocker.on { api.getCurrentUser() } runs { fakeUser() } //(2)
    }
}
  1. returns mocks the method to return the provided instance.

  2. runs mocks the method to run and return the result of the provided function.

Note that a method must be mocked to run without throwing an exception (there is no "relaxed" mode).

You can mock methods according to specific argument constraints:

mocker.on { api.update(isNotNull()) } returns true
mocker.on { api.update(isNull()) } runs { nullCounter++ ; false }

Available constraints are:

  • isAny is always valid (even with null values).

  • isNull and isNotNull check nullability.

  • isEqual and isNotEqual check regular equality.

  • isSame and isNotSame check identity.

Note that passing a non-constraint value to the function is equivalent to passing isEqual(value)

mocker.on { api.getUserById(42) } returns fakeUser()

is strictly equivalent to:

mocker.on { api.getUserById(isEqual(42)) } returns fakeUser()

Verification

You can check that mock functions has been run in order with verify.

val fakeUser = fakeUser()

mocker.on { db.loadUser(isAny()) } returns null
mocker.on { db.saveUser(isAny()) } returns Unit
mocker.on { api.getUserById(isAny()) } returns fakeUser

controller.onClickUser(userId = 42)

mocker.verify {
    db.loadUser(42)
    api.getUserById(42)
    db.saveUser(fakeUser)
}

You can of course use constraints (in fact, not using passing a constraint is equivalent to passing isEqual(value)):

mocker.verify {
    api.getUserById(isAny())
    db.saveUser(isNotNull())
}

The verify block must be exhaustive: it must lists all mocked functions that was called, in order. This means that you can easily check that no mocked methods were run:

mocker.verify {}

You can use clearCalls to clear the call log, in order to only verify for future method calls:

controller.onClickUser(userId = 42)
mocker.clearCalls() //(1)

controller.onClickDelete()
mocker.verify { db.deleteUser(42) }
  1. All mocked calls before this won’t be verified.

Custom constraints

You can define your own constraints:

fun ArgConstraintsBuilder.isStrictlyPositive(capture: MutableList<Int>? = null): Int =
    isValid(ArgConstraint(capture) {
        if (it >= 0) ArgConstraint.Result.Success
        else ArgConstraint.Result.Failure { "Expected a strictly positive value, got $it" }
    })

…​and use them in definition:

mocker.on { api.getSuccess(isStrictlyPositive()) } returns true
mocker.on { api.getSuccess(isAny()) } returns false

…​or in verification:

mocker.verify { api.getUserById(isStrictlyPositive()) }

Fakes

Caution
Only concrete trees (concrete classes containing concrete classes) can be faked!.

Data classes are ideal candidates for faking.

Requesting generation

You can declare that a class needs a specific faked data by using the @UsesFakes annotation.

@UsesFakes(User::class)
class MyTests {
}

Once a type appears in @UsesFakes, the processor will generate a fake function for it.

Instantiating

Once a class has been faked, you can get a new instance by calling its fake* corresponding function:

@UsesFakes(User::class)
class MyTests {
    val user = fakeUser()
}

Here are the rules the processor uses to generate fakes:

  • Nullable values are always null.

  • Boolean values are set to false.

  • Numeric values are set to 0.

  • String values are set to empty "".

  • Other non-nullable non-primitive values are faked.

Tip

By using a data class, you can easily tweak your fakes according to your needs:

val user = fakeUser().copy(id = 42)

Injecting your tests

Instead of creating your own mocks & fakes, it can be useful to inject them in your test class, especially if you have multiple tests using them.

@UsesFakes(User::class)
class MyTests {
    @set:Mock lateinit var db: Database
    @set:Mock lateinit var api: API

    @set:Fake lateinit var user: User

    lateinit var controller: Controller

    val mocker = Mocker()

    @BeforeTest fun setUp() {
        mocker.reset() //(1)
        this.injectMocks(mocker) //(2)
        controller = ControllerImpl(db, api) //(3)
    }
}
  1. Resets the mocker before any test (which removes all mocked behaviour & logged calls), so that each test gets a "clean" mocker.

  2. Injects mocks and fakes.

  3. Create classes to be tested with injected mocks & fakes.

As soon as a class T contains a @set:Mock or @set:Fake annotated property, a T.injectMocks(Mocker) function will be created by the processor.

Important
Don’t forget to reset the Mocker in a @BeforeTest method!

Setup

With KSP

Micro-Mock is a Kotlin Symbol Processor, so you need to apply KSP to use it.

Regular setup

build.gradle.kts
plugins {
    kotlin("multiplatform")
    id("com.google.devtools.ksp") version "1.6.0-RC-1.0.1-RC" //(1)
}

repositories {
    mavenCentral()
    maven(url = "https://raw.githubusercontent.com/Kodein-Framework/Micro-Mock/mvn-repo") //(3)
}

kotlin {
    jvm()
    ios()

    sourceSets {
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
                implementation("org.kodein.micromock:micro-mock:0.1") //(4)
            }
        }
    }
}

dependencies {
    "kspJvmTest"("org.kodein.micromock:micro-mock-processor:0.1") //(2)
    "kspIosX64Test"("org.kodein.micromock:micro-mock-processor:0.1") //(2)
    "kspIosArm64Test"("org.kodein.micromock:micro-mock-processor:0.1") //(2)
}
  1. Applying the KSP plugin

  2. Adding the processor on each required target

  3. Adding the custom maven repository (won’t be necessary after stable release)

  4. Adding the dependency to the Micro-Mock runtime

Buggy multiplatform

KSP for multiplatform is in beta, and KSP for the new JS/IR compiler is plainly not supported (yet).

If you need Micro-Mock for your tests but KSP is failing in your multiplatform project, here’s a trick that you can use:

build.gradle.kts
plugins {
    kotlin("multiplatform")
    id("com.google.devtools.ksp")
}

kotlin {
    jvm()
    ios()
    js(IR) {
        browser()
        nodejs()
    }

    sourceSets {
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
                implementation("org.kodein.micromock:micro-mock:0.1")
            }
            kotlin.srcDir("build/generated/ksp/jvmTest/kotlin") //(2)
        }
    }
}

dependencies {
    "kspJvmTest"(project(":micro-mock-processor")) //(1)
}

tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>>().all {
    if (name.startsWith("compileTestKotlin")) {
        dependsOn("kspTestKotlinJvm") //(3)
    }
}
  1. Apply the processor only on the JVM target

  2. Use KSP generated JVM sources on all targets

  3. Make compilation of all targets dependant on the JVM KSP processor

With the plugin

The Micro-Mock Gradle plugin applies the trick that only runs the processor on the JVM target and adds the generated sources to all targets. Note that this may collision with other Symbol Processors. This plugin will be deprecated once KSP properly supports Multiplatform & JS/IR.

settings.gradle.kts
pluginManagement {
    repositories {
        gradlePluginPortal()
        maven(url = "https://raw.githubusercontent.com/Kodein-Framework/Micro-Mock/mvn-repo") //(1)
    }
}
  1. Adding the custom maven repository (won’t be necessary after stable release)

build.gradle.kts
plugins {
    kotlin("multiplatform")
    id("org.kodein.micromock") version "0.1" //(1)
}

repositories {
    mavenCentral()
    maven(url = "https://raw.githubusercontent.com/Kodein-Framework/Micro-Mock/mvn-repo") //(2)
}

kotlin {
    jvm()
    ios()
    js(IR) {
        browser()
        nodejs()
    }

    sourceSets {
        val commonTest by getting {
            dependencies {
                implementation(kotlin("test"))
            }
        }
    }
}
  1. Applying the Micro-Mock plugin.

  2. Adding the custom maven repository (won’t be necessary after stable release)

Comments
  • Conflicting overloads, redeclarations, overload resolution ambiguity since version 1.5.0

    Conflicting overloads, redeclarations, overload resolution ambiguity since version 1.5.0

    When running the gradle command ./gradlew testReleaseUnitTest testDebugUnitTest (or running multiple tests of different modules in 1 command), I get compile issues (Redeclarations, overload resolution ambiguity)

    My test class is just a very simple basic UnitTest with mocks, and I am trying to execute the tests of multiple flavors/configurations at once. Running this at versions 1.1.0 to 1.4.0 of MocKMP gives no issues. When using version 1.5.0 or 1.6.0 i get the issues.

    In the build folders i see duplicate generated code:

    build
      \ generated
        \ ksp
          \ android
            \ androidDebugUnitTest
              \ <kotlin/package structure and generated code. IDE says the kotlin folder is part of [commonTest]>
            \ androidReleaseUnitTest
              \ <kotlin/package structure and generated code. IDE says the kotlin folder is part of [commonTest]>
    

    These are the issues i am seeing

    
    > Task :compileDebugUnitTestKotlinAndroid FAILED
    Execution optimizations have been disabled for task ':compileDebugUnitTestKotlinAndroid' to ensure correctness due to the following reasons:
      - Gradle detected a problem with the following location: '/<my_project_location>/build/generated/ksp/android/androidReleaseUnitTest/kotlin'. Reason: Task ':compileDebugUnitTestKotlinAndroid' uses this output of task ':kspReleaseUnitTestKotlinAndroid' without declaring an explicit or implicit dependency. This can lead to incorrect results being produced, depending on what order the tasks are executed. Please refer to https://docs.gradle.org/7.4.2/userguide/validation_problems.html#implicit_dependency for more details about this problem.
    e: /<my_project_location>/build/generated/ksp/android/androidDebugUnitTest/kotlin/com/example/HelloCoreTest_injectMocks.kt: (6, 1): Conflicting overloads: internal fun HelloCoreTest.injectMocks(mocker: Mocker): Unit defined in com.example in file HelloCoreTest_injectMocks.kt, internal fun HelloCoreTest.injectMocks(mocker: Mocker): Unit defined in com.example in file HelloCoreTest_injectMocks.kt
    e: /<my_project_location>/build/generated/ksp/android/androidDebugUnitTest/kotlin/com/example/MockHelloBrowser.kt: (6, 16): Redeclaration: MockHelloBrowser
    e: /<my_project_location>/build/generated/ksp/android/androidDebugUnitTest/kotlin/com/example/MockHelloNetworking.kt: (6, 16): Redeclaration: MockHelloNetworking
    e: /<my_project_location>/build/generated/ksp/android/androidReleaseUnitTest/kotlin/com/example/HelloCoreTest_injectMocks.kt: (6, 1): Conflicting overloads: internal fun HelloCoreTest.injectMocks(mocker: Mocker): Unit defined in com.example in file HelloCoreTest_injectMocks.kt, internal fun HelloCoreTest.injectMocks(mocker: Mocker): Unit defined in com.example in file HelloCoreTest_injectMocks.kt
    e: /<my_project_location>/build/generated/ksp/android/androidReleaseUnitTest/kotlin/com/example/MockHelloBrowser.kt: (6, 16): Redeclaration: MockHelloBrowser
    e: /<my_project_location>/build/generated/ksp/android/androidReleaseUnitTest/kotlin/com/example/MockHelloNetworking.kt: (6, 16): Redeclaration: MockHelloNetworking
    e: /<my_project_location>/src/commonTest/kotlin/com/example/HelloCoreTest.kt: (9, 33): Overload resolution ambiguity: 
    internal fun HelloCoreTest.injectMocks(mocker: Mocker): Unit defined in com.example in file HelloCoreTest_injectMocks.kt
    internal fun HelloCoreTest.injectMocks(mocker: Mocker): Unit defined in com.example in file HelloCoreTest_injectMocks.kt
    
    opened by HylkeB 5
  • Instantiation error on android test but native ios passes

    Instantiation error on android test but native ios passes

    I was trying to write a test using MocKmp and Decompose and I can't figure out why the Android test is failing, but the iOS one is passing. Below is the interface being mocked and a simple test.

    internal interface RootBlocChildBlocProvider {
    
        fun createBottomNavigationBloc(
            context: ComponentContext,
            output: (BottomNavigationBloc.Output) -> Unit
        ): BottomNavigationBloc
    
    }
    
    internal class RootBlocTest : TestsWithMocks() {
    
        override fun setUpMocks() = injectMocks(mocker)
    
        @Mock lateinit var rootResultUseCase: RootResultUseCase
        @Mock lateinit var blocProvider: RootBlocChildBlocProvider
        @Mock lateinit var bottomNavigationBloc: BottomNavigationBloc
        @Mock lateinit var activityLoggerBloc: ActivityLoggerBloc
        
        private val lifecycle = LifecycleRegistry().apply { resume() }
    
        val root: RootBloc by withMocks {
            RootBlocImpl(
                componentContext = DefaultComponentContext(lifecycle),
                rootResultUseCase = rootResultUseCase,
                blocProvider = blocProvider,
            )
        }
    
        @Test
        fun WHEN_created_THEN_BottomNavigationBloc_displayed() {
           //TODO invoke outputs for other tests
            val bottomNavOutputs = mutableListOf<(BottomNavigationBloc.Output) -> Unit>()
    
           // must be mocked before creation since done in the init
          // error is happening at this line when mocking
            every { blocProvider.createBottomNavigationBloc(isAny(), isAny(capture = bottomNavOutputs)) } returns bottomNavigationBloc
    
            val root = root
    
            assertTrue(root.activeChild is Child.BottomNavigation)
        }
    }
    

    From looking at the crash log, it seems to be caused by the ComponentContext although that was just an interface so was slightly confused. Not sure if this is a bug, misconfigured test, or maybe the usage of DefaultComponentContext? Any help would be appreciated.

    com.arkivanov.decompose.ComponentContext
    java.lang.InstantiationError: com.arkivanov.decompose.ComponentContext
    	at jdk.internal.reflect.GeneratedSerializationConstructorAccessor11.newInstance(Unknown Source)
    	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
    	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
    	at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
    	at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
    	at org.kodein.mock.PlatformJvmKt.unsafeValue(platformJvm.kt:46)
    	at org.kodein.mock.ArgConstraintsBuilder.toReturn(ArgConstraintsBuilder.kt:37)
    	at com.plusmobileapps.wolfpack.RootBlocTest$WHEN_created_THEN_BottomNavigationBloc_displayed$1.invoke(RootBlocTest.kt:113)
    	at com.plusmobileapps.wolfpack.RootBlocTest$WHEN_created_THEN_BottomNavigationBloc_displayed$1.invoke(RootBlocTest.kt:53)
    	at org.kodein.mock.Mocker.every(Mocker.kt:169)
    	at org.kodein.mock.tests.TestsWithMocks.every(TestsWithMocks.kt:54)
    	at com.plusmobileapps.wolfpack.RootBlocTest.WHEN_created_THEN_BottomNavigationBloc_displayed(RootBlocTest.kt:53)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    	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 com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:121)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
    	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
    	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    	at java.base/java.lang.Thread.run(Thread.java:832)
    
    
    
    opened by plusmobileapps 4
  • isAny() doesn't check the type

    isAny() doesn't check the type

    interface A
    interface B : A
    class Foo {
      fun consume(a: A) { println(a) }
    }
    // in tests
    @Test fun testMe() {
      val mockFoo = MockFoo()
      mockFoo.consume(object: A {})
      verify { mockFoo.consume(isAny<A>()) }
      // is equivalent to 
      verify { mockFoo.consume(isAny<B>()) }
      // and both will be pass even if the param is not an instance of B
    }
    

    I expect the check isAny<B>() to fail when an instance that doesn't implement B is used.

    I think isAny() should check the type instead of returning Success all the time, something like

        inline fun <reified T> isAny(capture: MutableList<T>? = null): ArgConstraint<T> =
            ArgConstraint(capture, "isAny") { if (it is T) ArgConstraint.Result.Success else ArgConstraint.Result.Failure({ "..." }) }
    

    (An alternative could be to provide a isInstanceOf<T>() next to isAny() if we don't want to change the current behavior.)

    opened by glureau 3
  • Multiple calls to `every{}` doesn't get applied

    Multiple calls to `every{}` doesn't get applied

    It would be nice if the every{} call can be overridden via multiple consecutive calls? Not sure if it can be done straight out of the box though.

    For example:

    interface Foo {
       fun bar(): Boolean
    }
    
    val impl: Foo = MockFoo(mocker);
    
    fun myTest() {
         every { impl.bar() } returns true
         val actual1 = impl.foo() // This will be true
         
         every { impl.bar() } returns false
         val actual2 = impl.foo() // This is expected to be false
    }
    
    

    Currently with latest version, actual2 will be equal to true, however it would be nice if the return value of bar() get's modified by the second call to every {}. This will help in setting up tests with basic return types in @Before() hook and then modify things as needed in the test.

    opened by kartik-prakash 2
  • Question: how to work with mock properties?

    Question: how to work with mock properties?

    For example, I have a class under test and a mock

    interface Sample {
        var sampleProperty: String
    }
    
    class UnderTest(val sample: Sample) {
        fun writeValue(data: String) {
            sample.sampleProperty = data
        }
    
        fun readValue(): String {
            return sample.sampleProperty
        }
    }
    

    I would like to write a test for methods writeValue and readValue, for example:

    class SampleTest : TestsWithMocks() {
        override fun setUpMocks() = injectMocks(mocker)
    
        @Mock
        lateinit var sample: Sample
    
        val testable: UnderTest by withMocks { UnderTest(sample) }
    
        @Test
        fun sampleWriteTest() {
            val data = "foo"
            testable.writeValue(data)
        }
    
        @Test
        fun sampleReadTest() {
            val data = testable.readValue()
        }
    }
    

    For now I'm getting MockSample.(get/set):sampleProperty has not been mocked error each time I run test.

    How to properly write rules in this case?

    opened by xpathexception 2
  • MockMP plugin with Gradle 7.2 gives error on multiplatform project

    MockMP plugin with Gradle 7.2 gives error on multiplatform project

    On sync, I get the error:

    Caused by: org.gradle.api.UnknownTaskException: Task with name 'kspDebugUnitTestKotlinAndroid' not found in project ':MobileShared'.
    	at org.kodein.mock.gradle.MocKMPGradlePlugin$apply$1$4.execute(MocKMPGradlePlugin.kt:67)
            at org.kodein.mock.gradle.MocKMPGradlePlugin$apply$1$4.execute(MocKMPGradlePlugin.kt:11)
    

    Taking out the plugin declaration, the sync goes through.

    //id("org.kodein.mock.mockmp") version Versions.mockmp
    

    MockMP version is 1.6.1

    opened by anar110 2
  • Mocked methods can't return null

    Mocked methods can't return null

    This seems to be a regression introduced in 1.6.0:

    https://github.com/Kodein-Framework/MocKMP/commit/95cf9675e5d4eb7e9a43a34edc01bc46222f57ae#r74049020

    opened by ankushg 2
  • Incompatibility with Kotlin 1.6.21

    Incompatibility with Kotlin 1.6.21

    The following problem can be reproduced creating a new KMM library that uses kotlin 1.6.21 and adding the plugin 1.4.0 (also happening with previous versions).

    When trying to build the project it fails with following message:

    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    ksp-1.6.10-1.0.4 is too old for kotlin-1.6.21. Please upgrade ksp or downgrade kotlin-gradle-plugin to 1.6.10.
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    A problem occurred configuring project ':shared'.
    > Could not create task ':shared:kspDebugUnitTestKotlinAndroid'.
       > Could not create task of type 'KspTaskJvm'.
          > org.jetbrains.kotlin.gradle.tasks.KotlinCompile.<init>(Lorg/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions;)V
    
    * Try:
    Run with --info or --debug option to get more log output. Run with --scan to get full insights.
    
    * Exception is:
    org.gradle.api.ProjectConfigurationException: A problem occurred configuring project ':shared'.
    	at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:75)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:68)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator.access$400(LifecycleProjectEvaluator.java:51)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate.run(LifecycleProjectEvaluator.java:195)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:105)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:325)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$withProjectLock$3(DefaultProjectStateRegistry.java:385)
    	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:211)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:385)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:366)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:324)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:91)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:63)
    	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:750)
    	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:150)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.ensureConfigured(DefaultProjectStateRegistry.java:298)
    	at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:41)
    	at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:57)
    	at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:50)
    	at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:64)
    	at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
    	at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:97)
    	at org.gradle.initialization.VintageBuildModelController.doBuildStages(VintageBuildModelController.java:77)
    	at org.gradle.initialization.VintageBuildModelController.prepareToScheduleTasks(VintageBuildModelController.java:64)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$prepareToScheduleTasks$0(DefaultBuildLifecycleController.java:104)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$withModelOrThrow$5(DefaultBuildLifecycleController.java:142)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.withModel(DefaultBuildLifecycleController.java:157)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.withModelOrThrow(DefaultBuildLifecycleController.java:140)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.prepareToScheduleTasks(DefaultBuildLifecycleController.java:102)
    	at org.gradle.internal.buildtree.DefaultBuildTreeWorkPreparer.scheduleRequestedTasks(DefaultBuildTreeWorkPreparer.java:33)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$doScheduleAndRunTasks$1(DefaultBuildTreeLifecycleController.java:83)
    	at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewTaskGraph(DefaultIncludedBuildTaskGraph.java:94)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.doScheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:82)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$fromBuildModel$0(DefaultBuildTreeLifecycleController.java:71)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:104)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.fromBuildModel(DefaultBuildTreeLifecycleController.java:69)
    	at org.gradle.tooling.internal.provider.runner.AbstractClientProvidedBuildActionRunner.runClientAction(AbstractClientProvidedBuildActionRunner.java:56)
    	at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:53)
    	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    	at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:47)
    	at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:69)
    	at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:91)
    	at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
    	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40)
    	at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:154)
    	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40)
    	at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
    	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:56)
    	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53)
    	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:56)
    	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
    	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79)
    	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
    	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:38)
    	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:211)
    	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:38)
    	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:103)
    	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
    	at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
    	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.lambda$execute$0(BuildSessionLifecycleBuildActionExecuter.java:56)
    	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69)
    	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:55)
    	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:37)
    	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
    	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
    	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:63)
    	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
    	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:58)
    	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42)
    	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
    	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
    	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
    	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
    	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
    	at org.gradle.util.internal.Swapper.swap(Swapper.java:38)
    	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
    	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
    	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
    	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
    	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:61)
    Caused by: org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreationException: Could not create task ':shared:kspDebugUnitTestKotlinAndroid'.
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.taskCreationException(DefaultTaskContainer.java:715)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.access$600(DefaultTaskContainer.java:76)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider.domainObjectCreationException(DefaultTaskContainer.java:707)
    	at org.gradle.api.internal.DefaultNamedDomainObjectCollection$AbstractDomainObjectCreatingProvider.tryCreate(DefaultNamedDomainObjectCollection.java:948)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider.access$1401(DefaultTaskContainer.java:654)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider$1.run(DefaultTaskContainer.java:680)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider.tryCreate(DefaultTaskContainer.java:676)
    	at org.gradle.api.internal.DefaultNamedDomainObjectCollection$AbstractDomainObjectCreatingProvider.calculateOwnValue(DefaultNamedDomainObjectCollection.java:929)
    	at org.gradle.api.internal.provider.AbstractMinimalProvider.get(AbstractMinimalProvider.java:84)
    	at org.gradle.api.internal.DefaultNamedDomainObjectCollection$AbstractDomainObjectCreatingProvider.get(DefaultNamedDomainObjectCollection.java:915)
    	at org.gradle.api.internal.DefaultDomainObjectCollection.addLater(DefaultDomainObjectCollection.java:284)
    	at org.gradle.api.internal.DefaultNamedDomainObjectCollection.addLater(DefaultNamedDomainObjectCollection.java:146)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.addLaterInternal(DefaultTaskContainer.java:761)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.access$900(DefaultTaskContainer.java:76)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$3.call(DefaultTaskContainer.java:416)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$3.call(DefaultTaskContainer.java:403)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.registerTask(DefaultTaskContainer.java:403)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.register(DefaultTaskContainer.java:375)
    	at com.google.devtools.ksp.gradle.KspGradleSubplugin.applyToCompilation(KspSubplugin.kt:286)
    	at org.jetbrains.kotlin.gradle.plugin.SubpluginEnvironment.addSubpluginOptions(SubpluginEnvironment.kt:82)
    	at org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler$configureTarget$3$1.invoke(KotlinPlugin.kt:878)
    	at org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler$configureTarget$3$1.invoke(KotlinPlugin.kt:873)
    	at org.jetbrains.kotlin.gradle.plugin.KotlinPluginKt$sam$org_gradle_api_Action$0.execute(KotlinPlugin.kt)
    	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext$CurrentApplication$1.execute(DefaultUserCodeApplicationContext.java:123)
    	at org.gradle.api.internal.DefaultCollectionCallbackActionDecorator$BuildOperationEmittingAction$1.run(DefaultCollectionCallbackActionDecorator.java:110)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.api.internal.DefaultCollectionCallbackActionDecorator$BuildOperationEmittingAction.execute(DefaultCollectionCallbackActionDecorator.java:107)
    	at org.gradle.api.internal.DefaultDomainObjectCollection.all(DefaultDomainObjectCollection.java:159)
    	at org.jetbrains.kotlin.gradle.plugin.KotlinPluginKt.forEachVariant(KotlinPlugin.kt:1186)
    	at org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler$configureTarget$3.invoke(KotlinPlugin.kt:873)
    	at org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler$configureTarget$3.invoke(KotlinPlugin.kt:872)
    	at org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginKt$whenEvaluated$2.execute(KotlinMultiplatformPlugin.kt:221)
    	at org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginKt$whenEvaluated$2.execute(KotlinMultiplatformPlugin.kt:221)
    	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext$CurrentApplication$1.execute(DefaultUserCodeApplicationContext.java:123)
    	at org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator$BuildOperationEmittingAction$1.run(DefaultListenerBuildOperationDecorator.java:152)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator$BuildOperationEmittingAction.execute(DefaultListenerBuildOperationDecorator.java:149)
    	at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:95)
    	at org.gradle.internal.event.BroadcastDispatch$ActionInvocationHandler.dispatch(BroadcastDispatch.java:83)
    	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:43)
    	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:245)
    	at org.gradle.internal.event.BroadcastDispatch$SingletonDispatch.dispatch(BroadcastDispatch.java:157)
    	at org.gradle.internal.event.AbstractBroadcastDispatch.dispatch(AbstractBroadcastDispatch.java:61)
    	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:346)
    	at org.gradle.internal.event.BroadcastDispatch$CompositeDispatch.dispatch(BroadcastDispatch.java:249)
    	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:141)
    	at org.gradle.internal.event.ListenerBroadcast.dispatch(ListenerBroadcast.java:37)
    	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    	at com.sun.proxy.$Proxy50.afterEvaluate(Unknown Source)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate$1.execute(LifecycleProjectEvaluator.java:187)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate$1.execute(LifecycleProjectEvaluator.java:184)
    	at org.gradle.api.internal.project.DefaultProject.stepEvaluationListener(DefaultProject.java:1428)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$NotifyAfterEvaluate.run(LifecycleProjectEvaluator.java:193)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.lambda$run$0(LifecycleProjectEvaluator.java:105)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$applyToMutableState$0(DefaultProjectStateRegistry.java:325)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.lambda$withProjectLock$3(DefaultProjectStateRegistry.java:385)
    	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:211)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:385)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.fromMutableState(DefaultProjectStateRegistry.java:366)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.applyToMutableState(DefaultProjectStateRegistry.java:324)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:91)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:63)
    	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:750)
    	at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:150)
    	at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.ensureConfigured(DefaultProjectStateRegistry.java:298)
    	at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:41)
    	at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:57)
    	at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:50)
    	at org.gradle.configuration.BuildTreePreparingProjectsPreparer.prepareProjects(BuildTreePreparingProjectsPreparer.java:64)
    	at org.gradle.configuration.BuildOperationFiringProjectsPreparer$ConfigureBuild.run(BuildOperationFiringProjectsPreparer.java:52)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
    	at org.gradle.configuration.BuildOperationFiringProjectsPreparer.prepareProjects(BuildOperationFiringProjectsPreparer.java:40)
    	at org.gradle.initialization.VintageBuildModelController.prepareProjects(VintageBuildModelController.java:97)
    	at org.gradle.initialization.VintageBuildModelController.doBuildStages(VintageBuildModelController.java:77)
    	at org.gradle.initialization.VintageBuildModelController.prepareToScheduleTasks(VintageBuildModelController.java:64)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$prepareToScheduleTasks$0(DefaultBuildLifecycleController.java:104)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$withModelOrThrow$5(DefaultBuildLifecycleController.java:142)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.withModel(DefaultBuildLifecycleController.java:157)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.withModelOrThrow(DefaultBuildLifecycleController.java:140)
    	at org.gradle.internal.build.DefaultBuildLifecycleController.prepareToScheduleTasks(DefaultBuildLifecycleController.java:102)
    	at org.gradle.internal.buildtree.DefaultBuildTreeWorkPreparer.scheduleRequestedTasks(DefaultBuildTreeWorkPreparer.java:33)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$doScheduleAndRunTasks$1(DefaultBuildTreeLifecycleController.java:83)
    	at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewTaskGraph(DefaultIncludedBuildTaskGraph.java:94)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.doScheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:82)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$fromBuildModel$0(DefaultBuildTreeLifecycleController.java:71)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:104)
    	at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.fromBuildModel(DefaultBuildTreeLifecycleController.java:69)
    	at org.gradle.tooling.internal.provider.runner.AbstractClientProvidedBuildActionRunner.runClientAction(AbstractClientProvidedBuildActionRunner.java:56)
    	at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:53)
    	at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
    	at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:47)
    	at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:69)
    	at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:91)
    	at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:41)
    	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:40)
    	at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:154)
    	at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:40)
    	at org.gradle.internal.buildtree.DefaultBuildTreeContext.execute(DefaultBuildTreeContext.java:40)
    	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.lambda$execute$0(BuildTreeLifecycleBuildActionExecutor.java:56)
    	at org.gradle.internal.buildtree.BuildTreeState.run(BuildTreeState.java:53)
    	at org.gradle.launcher.exec.BuildTreeLifecycleBuildActionExecutor.execute(BuildTreeLifecycleBuildActionExecutor.java:56)
    	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:61)
    	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor$3.call(RunAsBuildOperationBuildActionExecutor.java:57)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
    	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79)
    	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
    	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79)
    	at org.gradle.launcher.exec.RunAsBuildOperationBuildActionExecutor.execute(RunAsBuildOperationBuildActionExecutor.java:57)
    	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.lambda$execute$0(RunAsWorkerThreadBuildActionExecutor.java:38)
    	at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:211)
    	at org.gradle.launcher.exec.RunAsWorkerThreadBuildActionExecutor.execute(RunAsWorkerThreadBuildActionExecutor.java:38)
    	at org.gradle.tooling.internal.provider.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:103)
    	at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64)
    	at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46)
    	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.lambda$execute$0(BuildSessionLifecycleBuildActionExecuter.java:56)
    	at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:69)
    	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:55)
    	at org.gradle.tooling.internal.provider.BuildSessionLifecycleBuildActionExecuter.execute(BuildSessionLifecycleBuildActionExecuter.java:37)
    	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:36)
    	at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:25)
    	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:63)
    	at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:31)
    	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:58)
    	at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:42)
    	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:47)
    	at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:31)
    	at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:65)
    	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78)
    	at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75)
    	at org.gradle.util.internal.Swapper.swap(Swapper.java:38)
    	at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63)
    	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:84)
    	at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37)
    	at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104)
    	at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52)
    	at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
    	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:61)
    Caused by: org.gradle.api.tasks.TaskInstantiationException: Could not create task of type 'KspTaskJvm'.
    	at org.gradle.api.internal.project.taskfactory.TaskFactory$1.call(TaskFactory.java:95)
    	at org.gradle.api.internal.project.taskfactory.TaskFactory$1.call(TaskFactory.java:82)
    	at org.gradle.util.internal.GUtil.uncheckedCall(GUtil.java:454)
    	at org.gradle.api.internal.AbstractTask.injectIntoNewInstance(AbstractTask.java:204)
    	at org.gradle.api.internal.project.taskfactory.TaskFactory.create(TaskFactory.java:82)
    	at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory.create(AnnotationProcessingTaskFactory.java:48)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.createTask(DefaultTaskContainer.java:322)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer.access$200(DefaultTaskContainer.java:76)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider.createDomainObject(DefaultTaskContainer.java:697)
    	at org.gradle.api.internal.tasks.DefaultTaskContainer$TaskCreatingProvider.createDomainObject(DefaultTaskContainer.java:654)
    	at org.gradle.api.internal.DefaultNamedDomainObjectCollection$AbstractDomainObjectCreatingProvider.tryCreate(DefaultNamedDomainObjectCollection.java:941)
    	... 222 more
    Caused by: java.lang.NoSuchMethodError: org.jetbrains.kotlin.gradle.tasks.KotlinCompile.<init>(Lorg/jetbrains/kotlin/gradle/dsl/KotlinJvmOptions;)V
    	at com.google.devtools.ksp.gradle.KspTaskJvm.<init>(KspSubplugin.kt:425)
    	at com.google.devtools.ksp.gradle.KspTaskJvm_Decorated.<init>(Unknown Source)
    	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    	at org.gradle.internal.instantiation.generator.AsmBackedClassGenerator$InvokeConstructorStrategy.newInstance(AsmBackedClassGenerator.java:2070)
    	at org.gradle.internal.instantiation.generator.AbstractClassGenerator$GeneratedClassImpl$GeneratedConstructorImpl.newInstance(AbstractClassGenerator.java:486)
    	at org.gradle.internal.instantiation.generator.DependencyInjectingInstantiator.doCreate(DependencyInjectingInstantiator.java:64)
    	at org.gradle.internal.instantiation.generator.DependencyInjectingInstantiator.newInstanceWithDisplayName(DependencyInjectingInstantiator.java:50)
    	at org.gradle.api.internal.project.taskfactory.TaskFactory$1.call(TaskFactory.java:88)
    	... 232 more
    
    opened by franmontiel 2
  • Expose every {} publicly

    Expose every {} publicly

    I'm trying to define some common mocking methods that I use in many tests. I'd like to be able to write something like

    fun TestsWithMocks.defaultMockListener(mockListener: Listener) {
        every { mockListener.didStart(isAny(), isAny()) } returns Unit
        every { mockListener.didProgress(isAny(), isAny()) } returns Unit
        // ....
    

    But actually the every method is protected so I can't use it that easily. A workaround can be to use the mocker (defined publicly):

    fun TestsWithMocks.defaultMockListener(mockListener: Listener) {
        mocker.every { mockListener.didStart(isAny(), isAny()) } returns Unit
        mocker.every { mockListener.didProgress(isAny(), isAny()) } returns Unit
        // ....
    

    Since mocker is public on TestsWithMocks, it seems fair to me to make the shortcut methods public too.

    opened by glureau 2
  • JVM: isAny() (and other methods) doesn't work on interfaces

    JVM: isAny() (and other methods) doesn't work on interfaces

    interface Bar
    class Foo { fun consume(bar: Bar) }
      // in a test
      mocker.verify { foo.consume(isAny<Bar>()) } // throws a java.lang.InstantiationError
    

    Objenesis can instantiate classes but I think it cannot instantiate interface as far as I can tell:

        class Foo
        interface Bar
        val cl = ObjenesisStd(true).newInstance(Foo::class.java) // Builds a Foo
        val inter = ObjenesisStd(true).newInstance(Bar::class.java) // throws InstantiationError
    

    I suppose Mockmp should detect if it's an interface and may:

    • if the interface has a generated Mock, use the Mock class instead
    • if no mock has been generated for this interface, then provides an error message explaining the limitation and procedure to fix it.
    opened by glureau 2
  • Mock interfaces default methods.

    Mock interfaces default methods.

    Related to https://github.com/Kodein-Framework/MocKMP/issues/5

    equals and hashCode are actually used in the MocKMP code itself, so if we want to support them, we'll need a rework to ignore those calls.

    M1 support is optional, like the filtering of toString.

    opened by glureau 2
  • MocKMP not generating mocks

    MocKMP not generating mocks

    I had some issues that let MocKMP not to generate the mock classes for me.

    java.lang.NoSuchMethodError: 'void org.jetbrains.kotlin.codegen.state.KotlinTypeMapper.(org.jetbrains.kotlin.resolve.BindingContext, org.jetbrains.kotlin.codegen.ClassBuilderMode, java.lang.String, org.jetbrains.kotlin.config.LanguageVersionSettings, boolean, org.jetbrains.kotlin.config.JvmTarget, boolean, kotlin.jvm.functions.Function1, kotlin.jvm.functions.Function1, int, kotlin.jvm.internal.DefaultConstructorMarker)'

    work around, I set the plugin for ksp in the main build.gradle.kts gradle file, this forces MocKMP to use compatible ksp version, didn't want to go route of adding ksp directly like in your docs plugins { //trick: for the same plugin versions in all sub-modules

    id("com.google.devtools.ksp") version "1.7.20-Beta-1.0.6"
    

    }

    after that it worked!

    also this link was helpful https://github.com/google/ksp/issues/1050

    opened by cbukenya 0
  • Call count for mocks

    Call count for mocks

    Are there any plans to add the ability of verifying how many times an expectation was called? Sometimes a simple yes/no is not enough to track down some unexpected behaviour. Keep up the great work. 🙌

    opened by afonsograca 0
  • Unable to run tests with mock on iOS

    Unable to run tests with mock on iOS

    I will shortly share a sample project on this, however when running tests for iOS in a multiplatform project, tests are passing for android but failing for iOS with the following error:

    Uncaught Kotlin exception: org.kodein.mock.Mocker.MockingException: <My mocked class>.itsFunction() has not been mocked
    Invalid connection: com.apple.coresymbolicationd
    

    Anyone has seen that before or know how to resolve this?

    opened by kartik-prakash 3
  • Getting NullPointerExceptions

    Getting NullPointerExceptions

    We have a bunch of tests flickering because sometimes MocKMP throws a NullPointerException:

    java.lang.NullPointerException
    	at org.kodein.mock.Mocker.process(Mocker.kt:76)
    	at org.kodein.mock.Mocker.registerSuspend(Mocker.kt:309)
    	at org.kodein.mock.Mocker.registerSuspend$default(Mocker.kt:148)
    
    opened by benkuly 5
  • Invalid mock generation for functions with typealiased return types

    Invalid mock generation for functions with typealiased return types

    typealias SampleIntKeyMap<T> = Map<Int, T>
    
    interface Sample {
        fun sample(): SampleIntKeyMap<String>
    }
    

    Generated mock implemenation for this sample has invalid type T as Map#value type:

    import org.kodein.mock.Mocker
    
    internal class MockSample(
        private val mocker: Mocker,
    ) : Sample {
        public override fun sample(): Map<Int, T> = this.mocker.register( //<=== Map<Int, String> or SampleIntKeyMap<String> is expected
            receiver = this,
            method = "sample()"
        )
    
        public override fun toString(): String = this.mocker.register(
            receiver = this,
            method = "toString()",
            default = { super.toString() }
        )
    }
    
    
    opened by xpathexception 3
  • org.kodein.mock:mockmp-test-helper-jvm conflicts with org.jetbrains.kotlin:kotlin-test-junit5 during jvmTest

    org.kodein.mock:mockmp-test-helper-jvm conflicts with org.jetbrains.kotlin:kotlin-test-junit5 during jvmTest

    org.kodein.mock:mockmp-test-helper-jvm contains org.jetbrains.kotlin:kotlin-test-junit as a dependency.

    org.jetbrains.kotlin:kotlin-test-junit5 and org.jetbrains.kotlin:kotlin-test-junit conflict with each other.

    When project configured to use junit5 and we add mocKMP helper to it then we'll get compile time exception on running jvmTest:

    Execution failed for task ':jvmTest'.
    > Could not resolve all files for configuration ':jvmTestRuntimeClasspath'.
       > Could not resolve org.jetbrains.kotlin:kotlin-test-junit5:1.7.10.
         Required by:
             project : > org.jetbrains.kotlin:kotlin-test:1.7.10
          > Module 'org.jetbrains.kotlin:kotlin-test-junit5' has been rejected:
               Cannot select module with conflict on capability 'org.jetbrains.kotlin:kotlin-test-framework-impl:1.7.10' also provided by [org.jetbrains.kotlin:kotlin-test-junit:1.7.0(junitRuntime)]
       > Could not resolve org.jetbrains.kotlin:kotlin-test-junit:1.7.0.
         Required by:
             project : > org.kodein.mock:mockmp-test-helper:1.8.1 > org.kodein.mock:mockmp-test-helper-jvm:1.8.1
          > Module 'org.jetbrains.kotlin:kotlin-test-junit' has been rejected:
               Cannot select module with conflict on capability 'org.jetbrains.kotlin:kotlin-test-framework-impl:1.7.0' also provided by [org.jetbrains.kotlin:kotlin-test-junit5:1.7.10(junit5Runtime)]
    

    Reproducer:

    build.gradle.kts:

    plugins {
        kotlin("multiplatform") version "1.7.10"
        id("org.kodein.mock.mockmp") version "1.8.1"
    }
    
    group = "com.example"
    version = "1.0-SNAPSHOT"
    
    repositories {
        mavenCentral()
    }
    
    mockmp {
        usesHelper = true
    }
    
    kotlin {
        jvm {
            compilations.all {
                kotlinOptions.jvmTarget = "1.8"
            }
            withJava()
            testRuns["test"].executionTask.configure {
                useJUnitPlatform()
            }
        }
        js(BOTH) {
            browser {
                commonWebpackConfig {
                    cssSupport.enabled = true
                }
            }
        }
    
        sourceSets {
            val commonMain by getting
            val commonTest by getting {
                dependencies {
                    implementation(kotlin("test"))
                }
            }
            val jvmMain by getting
            val jvmTest by getting
            val jsMain by getting
            val jsTest by getting
        }
    }
    

    src/commonTest/kotlin/com/example/ExampleTest.kt:

    package com.example
    
    import kotlin.test.Test
    import kotlin.test.assertEquals
    
    class ExampleTest {
    
        @Test
        fun should_work() {
            assertEquals(1,1)
        }
    }
    

    Switching to Junit4 (useJUnitPlatform()' -> 'useJUnit()) or removing mocKMP helper (usesHelper = true -> usesHelper = false) make test runnable again.

    opened by vdshb 3
Releases(v1.11.0)
  • v1.11.0(Dec 5, 2022)

  • 1.10.0(Oct 5, 2022)

  • v1.10.0-kotlin-1.7.20-RC(Sep 19, 2022)

  • v1.9.0(Sep 16, 2022)

    • Kotlin 1.7.10
    • Support for JUnit5 with the new mockmp-test-helper-junit5 artifact (#31)
    • Fixed support for suspend methods with default implementation (#32)
    • Ease the mocking of var properties (#33)
    • Added standard MP collections to builtins (#35)
    • Make the Gradle plugin use JVM as default target when both JVM & Android are applied.
    Source code(tar.gz)
    Source code(zip)
  • v1.8.1(Jul 12, 2022)

  • v1.8.0(Jun 21, 2022)

  • v1.7.0(May 26, 2022)

    • Fix #21: Faking data classes with type aliases.
    • Supports faking generic data classes.
    • Fix #23: duplicated code when running multiple test configurations of the same JVM target.
    Source code(tar.gz)
    Source code(zip)
  • v1.6.1(May 23, 2022)

  • v1.6.0(May 12, 2022)

  • v1.5.0(May 6, 2022)

    BREAKING CHANGE: ArgConstraint.description is now () -> String instead of simply String. This only impacts you if you have defined custom argument constraints.

    #13: Fixes wrongful assertion error when verifying using a mock as a parameter of an argument contraint (such as verify { mock.call(isEqual(otherMock)) }). ArgConstraints.description is now resolved lazily. In case of assertion failure, it is also resolved outside of verification mode. Note that the mocker now throws MockerVerificationAssertionError (which resolve their message lazily).

    #15: Fixes bad code generation when mocking an interface that uses typealias.

    #16: Fixes the absence of annotations in generated code. Annotations are now copied verbatim in the generated code.

    #17: Compiled with Kotlin 1.6.20 and KSP 1.6.21-1.0.5

    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Mar 25, 2022)

    #10: Introducing the isInstanceOf argument constraint #11: Introducing @FakeProvider to provide fakes of types with private constructor (see https://github.com/Kodein-Framework/MocKMP#providing-fake-instances) #12: Reworked TestsWithMocks methods encapsulation to make them more consistent.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Mar 8, 2022)

    • Support for mocked function arguments (via argument constraints) of type interface, sealed type, abstract class, & Array. All argument types should be supported. If you find an argument type that cannot be emulated with an argument contraint, please open an issue. The Mocker.useReference function only exists as a way to not be blocked while waiting for a fix.

    • Support for optional mocking of interfaces default implementation. Note that a call to a non-mocked function with a default value will execute as expected, but will not be logged by the mocker, and therefore cannot be verified. If you need to verify, you need to mock.

    • Trying to verify a function that was not previously mocked is now a MockingException. It used to throw an AssertionException stating that there wasn't any call to the function. Since the function was not mocked, it could not be otherwise. The error presentation was misleading and could lead to misinterpretation, especially with interface default methods. It now clearly states that you cannot verify a non-mocked function.

    • Updated KSP to 1.0.4

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Feb 8, 2022)

  • v1.1.0(Feb 1, 2022)

    • #1: Fake generation now support functional types
    • #2: Proper support for KMM projects with Android plugin (rather than just a JVM target)
    • Better support for KSP error system. Error stack traces are shown if the throwErrors property is set to true in the Gradle plugin.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Dec 17, 2021)

    • Renamed project to MocKMP
    • Kotlin 1.6.10
    • Forces every & verify declarations to be either all constraints or all non-constraints (limitations is imposed by Kotlin/Native).
    Source code(tar.gz)
    Source code(zip)
  • v0.7.0(Nov 22, 2021)

  • v0.6.0(Nov 19, 2021)

  • v0.5.0(Nov 18, 2021)

    • Kotlin 1.6.0
    • Renames on to every to align with standards
    • Allows the annotation on properties (without set: prefix).
    • Introduces the TestWithMocks test helper class
    • Gradle plugin adds the dependencies repository, and supports optional adding of the test-helper dependency.
    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(Nov 16, 2021)

  • v0.4.0(Nov 15, 2021)

  • v0.3.0(Nov 15, 2021)

  • v0.2.0(Nov 15, 2021)

Owner
null
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
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
mocking library for Kotlin

Kotlin Academy articles Check the series of articles "Mocking is not rocket science" at Kt. Academy describing MockK from the very basics of mocking u

MockK 4.8k Jan 3, 2023
A programmer-oriented testing framework for Java.

JUnit 4 JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. For more infor

JUnit 8.4k Jan 9, 2023
Android Unit Testing Framework

Robolectric is the industry-standard unit testing framework for Android. With Robolectric, your tests run in a simulated Android environment inside a

Robolectric 5.6k Jan 3, 2023
PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.

Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability. Often testability corresponds to go

PowerMock 3.9k Jan 5, 2023
A powerful test framework for Android

Cafe A powerful test framework for Android named Case Automated Framework for Everyone. Home Page http://baiduqa.github.com/Cafe/ How to make Cafe dow

Baidu 367 Nov 22, 2022
A programmer-oriented testing framework for Java.

JUnit 4 JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. For more infor

JUnit 8.4k Dec 28, 2022
A powerful test framework for Android

Cafe A powerful test framework for Android named Case Automated Framework for Everyone. Home Page http://baiduqa.github.com/Cafe/ How to make Cafe dow

Baidu 367 Nov 22, 2022
PowerMock is a Java framework that allows you to unit test code normally regarded as untestable.

Writing unit tests can be hard and sometimes good design has to be sacrificed for the sole purpose of testability. Often testability corresponds to go

PowerMock 3.9k Jan 2, 2023
Selenium WebDriver and Appium based Web, Mobile (Android, iOS) and Windows desktop Automation Framework with BDD & Non-BDD implementation support

Selenium WebDriver and Appium based Web, Mobile (Android, iOS) and Windows desktop Automation Framework with BDD & Non-BDD implementation support

null 10 Dec 5, 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
Morsa: Jetpack Compose UI Testing Framework

Morsa: Jetpack Compose UI Testing Framework Test library to ease UI testing with Jetpack Compose Purpose This library aims to add some useful wrappers

HyperDevs 10 Dec 3, 2022
Snapshot Testing framework for Kotlin.

KotlinSnapshot Snapshot Testing framework for Kotlin. What is this? Snapshot testing is an assertion strategy based on the comparision of the instance

Pedro Gómez 157 Nov 13, 2022
D-KMP Architecture official sample: it uses a shared KMP ViewModel and Navigation for Compose and SwiftUI apps.

D-KMP architecture - official sample This is the official sample of the D-KMP architecture, presenting a simple master/detail app, for Android, iOS an

null 594 Jan 3, 2023
Raccoon is a lightweight response mocking framework that can be easily integrated into the Android UI tests.

Raccoon Medium Articles Checkout these article to get more insights about this library: How to integrate this in your Android Test Why Raccoon? There

Joseph James 52 Aug 15, 2022
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
🐦 Loritta's Social media relayer via Discord Webhooks micro-service

?? SocialRelayer ?? SocialRelayer is a social media relayer to Discord via webhooks, pulling Loritta's guild configurations to automatically register

Loritta 6 Jun 2, 2022
Micro Template 📃 A very tiny and simple text templating library for Kotlin.

Micro Template ?? A very tiny and simple text templating library for Kotlin. It has very limited features, so it's intended to be used for short templ

Matteo Mirk 24 Aug 20, 2022
Microservice-arch - Basic micro service architecture using spring boot

Readme 4 applications are created: discovery-service: every application register

Melvin Zottola 1 Jan 8, 2022