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

Ste*_*han 13 junit android robolectric kotlin

我在一个使用Robolectric的地方进行了测试,该例子在Android Studio中成功,但是在命令行上却没有。

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

//How the cipher is created
val mockCipher = object : Cipher(MockCipherSpi(), null, null) {}
Run Code Online (Sandbox Code Playgroud)

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())
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试失败的原因是,当我尝试从密码中获取IV时,我得到了一个空指针异常:

cipher.parameters.getParameterSpec(IvParameterSpec::class.java).iv
Run Code Online (Sandbox Code Playgroud)

这对于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)
Run Code Online (Sandbox Code Playgroud)

似乎javax.crypto.Cipherandroid.jar中有两个,而jce.jar中有一个,我假设AS正在使用一个,而gradle命令则是另一个。

我是否必须告诉gradle使用其他广口瓶,否则可以解决此问题吗?

Fco*_* P. 1

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

  • 是的,这就是我使用 Robolectric 的原因。 (4认同)
  • 但这并不能解释为什么它可以与 Android Studio 一起使用,它也不会在设备上执行测试。 (2认同)