【问题标题】:Android Studio Arctic Fox unable to run JUnit configuration with mockkAndroid Studio 北极狐无法使用 mockk 运行 JUnit 配置
【发布时间】:2021-10-22 14:32:23
【问题描述】:

我刚刚将我的 Android Studio 升级到最新版本。目前我猜我的一些测试类会产生不稳定的测试结果,我想像在 Android Studio 4.2 中一样在 Android Studio 中运行重复模式。但是我发现我得到了以下异常

即使我尝试了一个简单的测试类,我仍然得到这个错误。我使用 Gradle Test runner 运行,它按预期工作,但我无法使用它重复运行测试类以查看我的测试类中是否有任何片状结果

感谢任何评论或建议:)


java.lang.NoClassDefFoundError: io/mockk/proxy/MockKAgentFactory

    at io.mockk.impl.JvmMockKGateway.<init>(JvmMockKGateway.kt:198)
    at io.mockk.impl.JvmMockKGateway.<clinit>(JvmMockKGateway.kt:186)
    at com.example.testCorrect(Student.kt:24)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: java.lang.ClassNotFoundException: io.mockk.proxy.MockKAgentFactory
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
    ... 68 more
import io.mockk.mockk
import junit.framework.Assert.assertEquals
import org.junit.jupiter.api.Test

class StudentTest {
    @Test
    fun testCorrect() {
        val mockStudent = mockk<Student>()
        assertEquals(1,1)
    }
}

class Student(
    val name:String
)

更新:

我只是创建了一个 Hello World 项目并使用上面提到的简单配置。在“Gradle Test Runner”配置中,它可以工作。但在“JUnit”配置中,出现同样的错误

【问题讨论】:

  • 您是否尝试过使缓存失效并清理和重建项目?
  • 是的,我尝试了很多次,但没有成功

标签: android android-studio junit5 mockk


【解决方案1】:
Caused by: java.lang.ClassNotFoundException: io.mockk.proxy.MockKAgentFactory
   at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
   at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
   at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)

这是错误部分。 这是说类未找到异常,这意味着在某处提到了一个类,但如果没有找到或不存在。 或者,如果您正在使用一个实现,请删除该实现并重新放置它们。 这对我有用。 甚至我也面临同样的问题。

【讨论】:

  • 感谢您的建议,但运气不佳:(
【解决方案2】:

我想到了两个不同的问题/解决方案。

  1. 您可能忘记在 Gradle 配置中添加 mockk,如下所示:
testImplementation "io.mockk:mockk:{version}"

可能在以前的 Android Studio 中,它是从 Gradle 缓存中提供的。


  1. 我不知道为什么,但每次我第一次打开一个项目并且在我的构建中遇到一些 CNF 异常时,Arctic Fox 都会切换到我自定义安装的 JDK (1.8)。将其更改为嵌入式 JDK 后,一切正常。您可以转到 Preferences -> Build, Execution -> Build Tools -> Gradle 并将 Gradle SDK 更改为 Embedded JDK。正如我在您的屏幕截图中看到的那样,您还使用自定义安装的 JDK 11 运行测试。但是,mockk 不在 JDK 中,所以我想我的第一个建议可能更适合。

【讨论】:

  • 对于第一个建议,是的,我已经添加了它,它适用于“Gradle Test Runner”,但不适用于“JUnit”配置。我尝试了第二个建议,但没有奏效。
【解决方案3】:

您缺少测试运行器注释

@RunWith(MockitoJUnitRunner::class)

您还需要检查 build.gradle(app) 文件中的以下内容

testImplementation "org.mockito.kotlin:mockito-kotlin:3.2.0"
testImplementation 'org.mockito:mockito-inline:3.8.0'

【讨论】:

  • 不,我没有使用 mockito,如果我改用 mockito,这个解决方案也对我不起作用
  • 我发现这个 github 问题与你得到检查的错误有关 github.com/mockk/mockk/issues/605
【解决方案4】:

您能否尝试将其添加到您的应用级别 build.gradle:

testOptions {
    unitTests.all {
        useJUnitPlatform()
    }
}

【讨论】:

    【解决方案5】:

    android-gradle-plugin 在 IDE 项目导入期间删除运行时依赖项。早期的 Android Studio had 专用 IDE 功能扩展了 JUnit 运行配置类路径以包含运行时依赖项。现在您必须自己恢复类路径(或者最好避免在 Android 项目中运行 JUnit 配置)。 Android Studio 朝着将一切都委托给 Gradle 的方向发展(例如,参见 https://developer.android.com/studio/preview/features#bumblebee-unified-test-runner)。

    由于您使用的是 JUnit5,@RepeatedTest(10_000_000) 等可能是更简单的选择。

    TL;博士;

    MockKAgentFactory 可从io.mockk:mockk-agent-api 获得。我添加了以下内容以使您的示例正常工作:

        testImplementation "io.mockk:mockk:1.12.0"
        testImplementation "io.mockk:mockk-agent-jvm:1.12.0"
        testImplementation group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.5.30'
    

    诀窍在于 Android Gradle 插件。它构建(至少)2 个类路径:编译和运行时。 IDE Android 插件(在 Android Studio 中)仅从编译类路径导入库(删除运行时条目)。当使用 Gradle 运行器运行测试时,IDE 将执行委托给 gradle,而 Gradle 使用 Runtime 类路径调用测试。在 Android Studio 中使用 JUnit 运行测试时,JUnit 使用 IDE 模块的运行时类路径,正如 IDE 所见(它已经没有运行时库,因为它们在导入期间被删除)。检查外部库部分以查看添加到 IDE 项目中的确切内容。

    如果项目是常规 java 项目,IDE 将添加 mockk-agent-jvm 及其传递依赖项 mockk-agent-api。请注意 mockk-agent-jvmio.mockk:mockkRUNTIME 依赖项(请参阅 https://repo1.maven.org/maven2/io/mockk/mockk/1.12.0/mockk-1.12.0.pom)。 android-gradle-plugin 在导入期间删除运行时依赖项。从带有 gradle 运行配置的 IDE 运行时,您可以在任何测试方法的开头设置断点并检查堆栈跟踪。完整的测试运行时类路径在 gradle 调用 JUnitRunner 之前的一帧可用。例如。:

    【讨论】:

    • 感谢您的解释。这是唯一对我有用的解决方案。然而,在我添加这个之后,我遇到了其他第三方库的其他意外问题。当我需要重复运行一些测试用例时,我认为使用 Android 4.2 可能会更好。
    • 这是一个很好的答案,值得我给它一个赞成票!
    猜你喜欢
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    • 2021-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    相关资源
    最近更新 更多