mockito / mockito-kotlin

Using Mockito with Kotlin
MIT License
3.09k stars 198 forks source link

Some tests can not mock class in `Java17` #518

Open ArpitPatel009 opened 3 weeks ago

ArpitPatel009 commented 3 weeks ago

BEFORE

Java 11 gradle-7.5.1 AGP 7.4.2 mockitoAndroid = "5.3.1" mockitoKotlin = "5.1.0" App Debug & Release build successful ✅ Unit tests suit successful ✅

AFTER UPGRADE

Java 17 gradle-8.6 AGP 8.4.2 mockitoAndroid = "5.3.1" mockitoKotlin = "5.1.0" App Debug & Release build successful ✅ Some Unit tests unsuccessful ❌

Sample tests

import androidx.compose.ui.test.junit4.createEmptyComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import ca.manulife.MobileBanking.configuration.LocalConfig
import ca.manulife.MobileBanking.dashboard.ui.AccountDashboardViewModel
import ca.manulife.MobileBanking.helpers.DaggerHelper
import ca.manulife.MobileBanking.helpers.ServiceHelper
import ca.manulife.MobileBanking.insights.InsightContentViewModel
import ca.manulife.MobileBanking.login.views.LoginActivity
import ca.manulife.MobileBanking.rules.LazyActivityScenarioRule
import ca.manulife.MobileBanking.viewmodels.LiveData.CustomerDetailsViewModel
import ca.manulife.MobileBanking.viewmodels.LiveData.MainActivityViewModel
import com.manulife.chatbot.ChatbotRepository
import com.manulife.chatbot.models.live_data.ChatbotResponseViewModel
import com.manulife.chatbot.models.live_data.ChatbotViewModel
import com.manulife.chatbot.services.ChatbotServiceHelper
import kotlinx.coroutines.flow.MutableStateFlow
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.Is.`is`
import org.hamcrest.core.IsNull.notNullValue
import org.hamcrest.core.IsNull.nullValue
import org.junit.After
import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.robolectric.Shadows.shadowOf

@RunWith(AndroidJUnit4::class)
class MainActivityLogoutTests {
    @get:Rule
    val activityScenarioRule = LazyActivityScenarioRule(createEmptyComposeRule(), MainActivity::class.java)

    @Mock
    private lateinit var serviceHelper: ServiceHelper

    @Mock
    private lateinit var chatbot: ChatbotServiceHelper

    @Mock
    private lateinit var viewModel: MainActivityViewModel

    @Mock
    private val chatbotVm = mock<ChatbotViewModel>()

    @Mock
    private val chatbotReponseVM = mock<ChatbotResponseViewModel>()

    @Mock
    private val customerDetailsViewModel = mock<CustomerDetailsViewModel>()

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        viewModel = DaggerHelper.setViewModel(defaultAnswer = Answers.RETURNS_MOCKS) {
            on { config } doReturn LocalConfig()
        }
        val sf = MutableStateFlow(true)
        DaggerHelper.setViewModel<ChatbotViewModel>(defaultAnswer = Answers.RETURNS_MOCKS) {}
        DaggerHelper.setViewModel<ChatbotResponseViewModel>(defaultAnswer = Answers.RETURNS_MOCKS) {}
        DaggerHelper.setViewModel<CustomerDetailsViewModel>(defaultAnswer = Answers.RETURNS_MOCKS) {}
        DaggerHelper.setViewModel<AccountDashboardViewModel>(defaultAnswer = Answers.RETURNS_MOCKS) {
            on { isRefreshing } doReturn MutableStateFlow(true)
        }
        DaggerHelper.setViewModel<InsightContentViewModel>(defaultAnswer = Answers.RETURNS_MOCKS) {}

        ServiceHelper.setInstance(serviceHelper)
        ChatbotServiceHelper.setInstance(chatbot)

        activityScenarioRule.launch()
    }

    @After
    fun tearDown() {
        ServiceHelper.setInstance(null)
        ChatbotServiceHelper.setInstance(null)
        DaggerHelper.reset()
    }

    @Test
    fun logout_closesTheActivity() {
        // arrange

        // act
        activityScenarioRule.scenario.onActivity {
            it.logout()

            // assert
            assertThat("MainActivity should finish() when it opens the LoginActivity",
                    it.isFinishing, `is`(true))
        }
    }

}

Error

org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class fake.package.name.resourses.Resource.

If you're not sure why you're getting this error, please open an issue on GitHub.

Java               : 17
JVM vendor name    : JetBrains s.r.o.
JVM vendor version : 17.0.10+0-17.0.10b1087.21-11572160
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 17.0.10+0-17.0.10b1087.21-11572160
JVM info           : mixed mode
OS name            : Mac OS X
OS version         : 14.5

You are seeing this disclaimer because Mockito is configured to create inlined mocks.
You can learn about inline mocks and their limitations under item #39 of the Mockito class javadoc.

Underlying exception : org.mockito.exceptions.base.MockitoException: Unsupported settings with this type 'fake.package.name.resourses.Resource'
    at fake.package.name.viewmodels.LiveData.MainActivityViewModel.getAccounts(MainActivityViewModel.kt:29)
    at fake.package.name.MainActivity.setUpBottomBarFragments(MainActivity.java:489)
    at fake.package.name.MainActivity.onCreate(MainActivity.java:216)
    at android.app.Activity.performCreate(Activity.java:8290)
    at android.app.Activity.performCreate(Activity.java:8269)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
    at org.robolectric.android.internal.RoboMonitoringInstrumentation.callActivityOnCreate(RoboMonitoringInstrumentation.java:295)
    at org.robolectric.android.controller.ActivityController.lambda$create$0(ActivityController.java:130)
    at org.robolectric.shadows.ShadowPausedLooper.runPaused(ShadowPausedLooper.java:204)
    at org.robolectric.android.controller.ActivityController.create(ActivityController.java:128)
    at org.robolectric.android.controller.ActivityController.create(ActivityController.java:138)
    at org.robolectric.android.internal.RoboMonitoringInstrumentation.startActivitySyncInternal(RoboMonitoringInstrumentation.java:108)
    at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:35)
    at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:40)
    at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:362)
    at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:202)
    at fake.package.name.rules.LazyActivityScenarioRule._init_$lambda$1(LazyActivityScenarioRule.kt:40)
    at fake.package.name.rules.LazyActivityScenarioRule.launch(LazyActivityScenarioRule.kt:60)
    at fake.package.name.MainActivityLogoutTests.setUp(MainActivityLogoutTests.kt:79)
    at java.base@17.0.10/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base@17.0.10/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base@17.0.10/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at app//org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at app//org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at app//org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at app//org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
    at app//org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at app//org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1$evaluate$1.invoke(AndroidComposeTestRule.android.kt:272)
    at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1$evaluate$1.invoke(AndroidComposeTestRule.android.kt:271)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$AndroidComposeUiTestImpl.withDisposableContent(ComposeUiTest.android.kt:491)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1$1$1.invoke(ComposeUiTest.android.kt:323)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withComposeIdlingResource(ComposeUiTest.android.kt:375)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withComposeIdlingResource(ComposeUiTest.android.kt:228)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1$1.invoke(ComposeUiTest.android.kt:322)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withWindowRecomposer(ComposeUiTest.android.kt:349)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withWindowRecomposer(ComposeUiTest.android.kt:228)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1$1.invoke(ComposeUiTest.android.kt:321)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.withTestCoroutines(ComposeUiTest.android.kt:362)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.access$withTestCoroutines(ComposeUiTest.android.kt:228)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1$1.invoke(ComposeUiTest.android.kt:320)
    at androidx.compose.ui.test.junit4.IdlingStrategy.withStrategy(IdlingStrategy.android.kt:52)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1$1.invoke(ComposeUiTest.android.kt:319)
    at androidx.compose.ui.test.junit4.IdlingResourceRegistry.withRegistry(IdlingResourceRegistry.jvm.kt:157)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment$runTest$1.invoke(ComposeUiTest.android.kt:318)
    at androidx.compose.ui.test.junit4.ComposeRootRegistry.withRegistry(ComposeRootRegistry.android.kt:146)
    at androidx.compose.ui.test.AndroidComposeUiTestEnvironment.runTest(ComposeUiTest.android.kt:317)
    at androidx.compose.ui.test.junit4.AndroidComposeTestRule$apply$1.evaluate(AndroidComposeTestRule.android.kt:271)
    at app//org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:54)
    at app//org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at app//org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:580)
    at app//org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:287)
    at app//org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:99)
    at java.base@17.0.10/java.util.concurrent.FutureTask.run(Unknown Source)
    at java.base@17.0.10/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base@17.0.10/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base@17.0.10/java.lang.Thread.run(Unknown Source)
    Suppressed: org.robolectric.android.internal.AndroidTestEnvironment$UnExecutedRunnablesException: Main looper has queued unexecuted runnables. This might be the cause of the test failure. You might need a shadowOf(Looper.getMainLooper()).idle() call.
Caused by: org.mockito.exceptions.base.MockitoException: Unsupported settings with this type 'fake.package.name.resourses.Resource'
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
    at fake.package.name.viewmodels.LiveData.MainActivityViewModel.getAccounts(MainActivityViewModel.kt:29)
    at fake.package.name.MainActivity.setUpBottomBarFragments(MainActivity.java:489)
    at fake.package.name.MainActivity.onCreate(MainActivity.java:216)
    at android.app.Activity.$$robo$$android_app_Activity$performCreate(Activity.java:8290)
    at android.app.Activity.performCreate(Activity.java)
    at android.app.Activity.$$robo$$android_app_Activity$performCreate(Activity.java:8269)
    at android.app.Activity.performCreate(Activity.java)
    at android.app.Instrumentation.$$robo$$android_app_Instrumentation$callActivityOnCreate(Instrumentation.java:1384)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java)
    at org.robolectric.android.internal.RoboMonitoringInstrumentation.callActivityOnCreate(RoboMonitoringInstrumentation.java:295)
    at org.robolectric.android.controller.ActivityController.lambda$create$0(ActivityController.java:130)
    at org.robolectric.shadows.ShadowPausedLooper.runPaused(ShadowPausedLooper.java:204)
    at org.robolectric.android.controller.ActivityController.create(ActivityController.java:128)
    at org.robolectric.android.controller.ActivityController.create(ActivityController.java:138)
    at org.robolectric.android.internal.RoboMonitoringInstrumentation.startActivitySyncInternal(RoboMonitoringInstrumentation.java:108)
    at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:35)
    at org.robolectric.android.internal.LocalActivityInvoker.startActivity(LocalActivityInvoker.java:40)
    at androidx.test.core.app.ActivityScenario.launchInternal(ActivityScenario.java:362)
    at androidx.test.core.app.ActivityScenario.launch(ActivityScenario.java:202)
    at fake.package.name.rules.LazyActivityScenarioRule._init_$lambda$1(LazyActivityScenarioRule.kt:40)
    at fake.package.name.rules.LazyActivityScenarioRule.launch(LazyActivityScenarioRule.kt:60)
    at fake.package.name.MainActivityLogoutTests.setUp(MainActivityLogoutTests.kt:79)
    at java.base@17.0.10/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base@17.0.10/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base@17.0.10/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base@17.0.10/java.lang.reflect.Method.invoke(Unknown Source)