android - Robolectric 在命令行上失败,但在 Android Studio 中成功

标签 android kotlin junit robolectric

我有一个测试,我使用 Robolectric,它在 Android Studio 中成功,但在命令行上没有。

我使用的是 Robolectric 4.2,测试涉及一个密码,我对此测试进行了部分模拟。

//How the cipher is created
val mockCipher = object : Cipher(MockCipherSpi(), null, null) {}

MockCipher 基本上只返回未加密的输入:

class MockCipherSpi : CipherSpi() {
...
    private val algorithmParametersSpi: AlgorithmParametersSpi? = object : AlgorithmParametersSpi() {
        ...
        override fun <T : AlgorithmParameterSpec?> engineGetParameterSpec(paramSpec: Class<T>?): T {
            return IvParameterSpec(byteArrayOf()) as T
        }
    }
    ...
    override fun engineGetParameters(): AlgorithmParameters {
        return object : AlgorithmParameters(algorithmParametersSpi, null, null) {
            init {
                init(byteArrayOf())
            }
        }
    }
}

我的测试失败的原因是当我尝试从密码中获取 IV 时出现空指针异常:

cipher.parameters.getParameterSpec(IvParameterSpec::class.java).iv

这对 Android Studio 非常有效,我什至可以调试它,但是从命令行使用 ./gradlew test 运行它会失败。

java.lang.NullPointerException
at javax.crypto.Cipher.<init>(Cipher.java:268)
at the place where I try to access the iv
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:601)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.robolectric.internal.SandboxTestRunner$2.evaluate(SandboxTestRunner.java:260)
at org.robolectric.internal.SandboxTestRunner.runChild(SandboxTestRunner.java:130)
at org.robolectric.internal.SandboxTestRunner.runChild(SandboxTestRunner.java:42)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.internal.SandboxTestRunner$1.evaluate(SandboxTestRunner.java:84)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:116)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:59)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:39)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy1.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:146)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:128)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:748)

似乎有两个 javax.crypto.Cipher 一个来自 android.jar,一个来自 jce.jar 我假设 AS 使用一个,另一个是 gradle 命令。

我是否必须告诉 gradle 使用其他 jar 或者我可以通过其他方式解决这个问题?

最佳答案

您正在尝试在桌面测试中使用来自 android SDK 的类。那总是会失败的。 Android SDK 具有 Java 开发工具包中根本没有的类。 Android jar 仅提供了一个用于开发目的的空 API,但要运行程序,您需要将它们执行到 android 设备中。在这种情况下,您将需要模拟整个调用,或者找到等效的桌面实现并在测试期间将 android 调用替换为桌面调用(可能通过将您的类分成两部分,例如逻辑和 API 访问)。鉴于您正在运行的方法暴露了原生(C 级)api,模拟整个 API 调用似乎是解决这个问题的最快方法。

关于android - Robolectric 在命令行上失败,但在 Android Studio 中成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56294961/

相关文章:

java - 未找到用户位置 :- latitude and longitude in android

android - 如何使用 twitter api 发推文?

kotlin - 在 Kotlin 中导入嵌套对象/对象函数

java - 要求 JUnit 在其调用的方法中抛出异常

spring - 为什么@SpringBootTest在构造函数注入(inject)中需要@Autowired

javascript - 使用 javascript 选择文本并显示 Android 的复制窗口

Android - 听数字键盘上的按键?

android - ARcore场景(非AR)如何识别旋转手势?

android - 与 Kotlin : ProcessDataBinding Unable to get public no-arg constructor 的数据绑定(bind)

java - 如何使用 Mockito 验证带有枚举参数的方法调用?