Android Studio Arctic Fox无法使用mockk运行JUnit配置

7

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

即使我尝试使用简单的测试类,我仍然会遇到这个错误。我使用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
)

enter image description here

更新:

我刚刚创建了一个Hello World项目,并使用如上所述的简单配置。在“Gradle测试运行器”配置中,它可以正常工作。但在“JUnit”配置中,发生了相同的错误。


你有尝试过清除缓存并进行项目清理和重建吗? - Kostas Andrianos
是的,我尝试过很多次,但运气不佳。 - Long Ranger
5个回答

10

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

由于您正在使用JUnit5,@RepeatedTest(10_000_000)或类似选项可能会更容易。

简而言之;

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插件。它至少构建了两个类路径:编译和运行时。IDE Android插件(在Android Studio中)仅从编译类路径导入库(运行时条目被删除)。当使用Gradle运行器运行测试时,IDE将执行委派给gradle,并且Gradle使用运行时类路径调用测试。在Android Studio中使用JUnit运行测试时,JUnit使用IDE模块的运行时类路径,因为它是由IDE看到的(在导入期间已经删除了运行时库)。检查“外部库”部分以查看确切添加到IDE项目的内容。 enter image description here 如果项目是常规Java项目,则IDE会添加mockk-agent-jvm及其传递依赖项mockk-agent-api。请注意,mockk-agent-jvm是io.mockk:mockk的运行时依赖项(参见https://repo1.maven.org/maven2/io/mockk/mockk/1.12.0/mockk-1.12.0.pom)。android-gradle-plugin在导入期间删除运行时依赖项。当使用gradle运行配置从IDE运行时,您可以在任何测试方法的开头设置断点并检查堆栈跟踪。完整的测试运行时类路径在JUnitRunner被gradle调用之前的一帧中可用。例如: enter image description here

谢谢您的解释。这是唯一对我有效的解决方案。然而,在我添加了这个之后,我遇到了其他第三方库的意外问题。我认为当我需要重复运行某些测试用例时,使用Android 4.2可能会更好。 - Long Ranger
1
这是一个很棒的答案,值得我给予更多的赞同! - IainCunningham

1

你可以尝试将以下内容添加到您应用程序级别的build.gradle文件中:

testOptions {
    unitTests.all {
        useJUnitPlatform()
    }
}

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)

这是错误的部分。 它表示找不到类异常,这意味着某个地方提到了一个类,但如果未找到或不存在,则会出现此问题。 或者,如果您正在使用实现,请删除实现并重新放置它们。 这对我有效。 我也遇到了同样的问题。


谢谢您的建议,但是没有成功 :( - Long Ranger

0

我脑海中浮现了两个不同的问题/解决方案。

  1. 你可能忘记在Gradle配置中添加mockk,像下面这样:
testImplementation "io.mockk:mockk:{version}"

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


  • 我不知道为什么,但每次我打开一个项目时,Arctic Fox会切换到我的自定义安装的JDK(1.8),并且我在构建中遇到了一些CNF异常。 将其更改为嵌入式JDK后,所有内容均按预期工作。 您可以转到首选项 -> 构建,执行 -> 构建工具 -> Gradle并将Gradle SDK更改为嵌入式JDK。 正如我在您的屏幕截图中所看到的那样,您也正在使用自定义安装的JDK 11运行测试。 但是,mockk不在JDK内,因此我认为我的第一个建议可能更适合。
  • Gradle JDK


    对于第一个建议,是的,我已经添加了它,并且可以使用“Gradle测试运行器”工作,但不能与“JUnit”配置一起使用。我尝试了第二个建议,但不起作用。 - Long Ranger

    -1

    你缺少了测试运行器的注解

    @RunWith(MockitoJUnitRunner::class)
    

    同时,您还需要检查您的 build.gradle(app) 文件是否包含以下内容

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

    不,我没有使用Mockito,如果我改用Mockk,这个解决方案也不适用于我。 - Long Ranger
    我发现了一个与你遇到的错误相关的 Github 问题,请查看 https://github.com/mockk/mockk/issues/605 - Hussain

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接