Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract method implementations cannot be mocked in Android instrumentation tests #1080

Closed
3 tasks done
steffandroid opened this issue Apr 17, 2023 · 2 comments · Fixed by #1081
Closed
3 tasks done

Comments

@steffandroid
Copy link
Contributor

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

Note: this issue was also raised in the comments of a similar but unrelated issue - #826 (comment)

Expected Behavior

I have some instrumentation tests where I'm mocking a subclass of an abstract class, and attempting to mock an abstract method that it overrides. This actually works just fine on older versions of Mockk (e.g. 1.12.3) but appears to have been broken by the support for value classes added in 1.12.5 (#849).

Current Behavior

The test fails with java.lang.AbstractMethodError: abstract method "boolean kotlin.reflect.KClass.isValue()".

Failure Information (for bugs)

Steps to Reproduce

Please provide detailed steps for reproducing the issue.

  1. Add an abstract class with an abstract method.
  2. Subclass this, and implement the method.
  3. Mock the method in a test.
  4. The error occurs.

Context

  • MockK version: 1.13.5
  • OS: Android 13
  • Kotlin version: 1.8.10
  • JDK version: 11
  • JUnit version: 4
  • Type of test: android instrumented test

Failure Logs

Stack trace

java.lang.AbstractMethodError: abstract method "boolean kotlin.reflect.KClass.isValue()"
at io.mockk.core.ValueClassSupport.isValue_safe(ValueClassSupport.kt:63)
at io.mockk.core.ValueClassSupport.getBoxedClass(ValueClassSupport.kt:32)
at io.mockk.impl.instantiation.JvmMockFactoryHelper.toDescription$mockk(JvmMockFactoryHelper.kt:156)
at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:26)
at io.mockk.proxy.android.advice.Advice.handle$lambda$0(Advice.kt:78)
at io.mockk.proxy.android.advice.Advice.$r8$lambda$y8tfHRaw6Qz3pR6YeNDVMHk1z1U(Unknown Source:0)
at io.mockk.proxy.android.advice.Advice$$ExternalSyntheticLambda0.call(Unknown Source:10)
at com.example.Test$Foo.bar(Unknown Source:33)
at com.example.Test$test$1.invoke(Test.kt:143)
at com.example.Test$test$1.invoke(Test.kt:143)
at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$1.invoke(RecordedBlockEvaluator.kt:25)
at io.mockk.impl.eval.RecordedBlockEvaluator$enhanceWithRethrow$1.invoke(RecordedBlockEvaluator.kt:78)
at io.mockk.impl.recording.JvmAutoHinter.autoHint(JvmAutoHinter.kt:23)
at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:40)
at io.mockk.impl.eval.EveryBlockEvaluator.every(EveryBlockEvaluator.kt:30)
at io.mockk.MockKDsl.internalEvery(API.kt:94)
at io.mockk.MockKKt.every(MockK.kt:143)
at com.exmple.Test.test(Test.kt:143)

Minimal reproducible code (the gist of this issue)

package com.example

import androidx.test.ext.junit.runners.AndroidJUnit4
import io.mockk.every
import io.mockk.mockk
import org.junit.Test

@RunWith(AndroidJUnit4::class)
class Test {

    @Test
    fun test() {
        val mockFoo: Foo = mockk()

        every { mockFoo.bar() } returns "blah"
    }

    abstract class AbsFoo {
        abstract fun bar(): String
    }

    class Foo : AbsFoo() {
        override fun bar() = "bar"
    }

}
Kudo added a commit to expo/expo that referenced this issue Apr 25, 2023
# Why

fix android instrumentation test error:
expo-modules-core: https://github.com/expo/expo/actions/runs/4770550299/jobs/8481882792
expo-updates: https://github.com/expo/expo/actions/runs/4785632925/jobs/8509073622


### expo-modules-core

```
expo.modules.JavaScriptViewModule > should_export_view_prototype[avd-31(AVD) - 12] FAILED 
	io.mockk.MockKException: no answer found for: AppContext(#1).getBackgroundCoroutineScope()
	at io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:93)

expo.modules.JavaScriptViewModule > view_functions_should_be_callable[avd-31(AVD) - 12] FAILED 
	io.mockk.MockKException: no answer found for: AppContext(#2).getBackgroundCoroutineScope()
	at io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:93)
```

### expo-updates

1. crashes from `mockDelegate.getCheckAutomaticallyConfiguration()`
2. https://github.com/expo/expo/blob/79c05375b8ae9149aa4dff456a3c25641a68f360/packages/expo-updates/android/src/androidTest/java/expo/modules/updates/logging/UpdatesLoggingTest.kt#L106 the line here is two rather than one: 

# How

- [core] answers mocked `getBackgroundCoroutineScope`
- [updates] my hypothesis is that mockk cannot [instantiate abstract classes](mockk/mockk#1080). after #22137, the `UpdatesConfiguration.CheckAutomaticallyConfiguration` is now an anonymous class. the workaround here is having a default implementation for `UpdatesConfiguration.CheckAutomaticallyConfiguration.toJSString()`.
- [updates] fix `@Before` does not be called in `UpdatesLoggingTest`.  in the `@Before` block, the test purges log and will make the test more reliable.

# Test Plan

ci passed
@MilanVidic
Copy link

We got this error when updating mockk from 1.12.3 to 1.13.5. We found out that issue was caused because we also had moshi library on version 1.12.0 which uses kotlin-reflect version 1.4.31. isValue was only added in Kotlin 1.5. So either adding direct dependency to kotlin-reflect version 1.8.21 or updating moshi to 1.15.0 worked.

@steffandroid
Copy link
Contributor Author

@MilanVidic thank you so much for pointing this out – I've now realised I was also facing the same issue in my codebase but with a different library (rx-tasks). Resolved by manually excluding the rogue dependency, as detailed in ashdavies/rx-tasks#26 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants