Android Studio 3.6.3/4.0/4.1/4.2配置Robolectric-3.8/4.3.1/4.5.1/4.6.1 Powermock-1.6.6单元测试环境

基础配置以及常见错误


目前版本的Android Studio 3.6.3/4.0/4.1/4.2使用Robolectric-3.8/4.3.1/4.5.1/4.6.1,只能配合Powermock-1.6.6,不能高于这个版本PowerMock ,尽管软件源中的版本已经更新升级到2.0.7版本了,但是Robolectric并没有及时更新依赖。尝试过使用最新版本的PowerMock,结果很多莫名的报错。

    // 单元测试
    testImplementation "com.android.support.test:runner:1.0.2"
    testImplementation "junit:junit:4.13.2"
    testImplementation "org.robolectric:robolectric:4.5.1"

    // 注意AndroidX环境下,不能引入shadows-supportv4,Jetifier转换的时候报错
    testImplementation "org.robolectric:shadows-supportv4:4.5.1"

    // MultiDex支持
    testImplementation "org.robolectric:shadows-multidex:4.5.1"
    
    // 此处版本更新需要特别小心,目前 robolectric 跟 powermock 存在兼容问题,
    // 需要固定的某些版本才能正常配合
    // 依赖关系参考 
    // https://github.com/robolectric/robolectric/wiki/Using-PowerMock
    testImplementation "org.powermock:powermock-module-junit4:1.6.6"
    testImplementation "org.powermock:powermock-module-junit4-rule:1.6.6"
    testImplementation "org.powermock:powermock-classloading-xstream:1.6.6"
    testImplementation "org.powermock:powermock-api-mockito:1.6.6"

如果 Windows 系统下出现如下提示,受限于Windows系统路径不能超过260个字符的限制

13:36 Error running 'xxxTest': Command line is too long. Shorten command line for xxxTest or also for Android JUnit default configuration.

貌似Windows 10 Build 14352版中已经可以通过修改注册表去除260字符的路径长度限制了。

在项目`/.idea/workspace.xml`文件中添加一行代码如下

<component name="PropertiesComponent">
    ...
    <property name="dynamic.classpath" value="true" />
</component>

对于使用MultiDex的应用,如果报告如下错误:

java.lang.RuntimeException: MultiDex installation failed (/var/folders/h6/4__l0pyn32j1mkkysynnxydr0000gn/T/robolectric-Method_xxxxxxxxxxxx_isCorrect4035485067136008322/com.xxxx.xxxx.app-sourceDir (Is a directory)).

	at android.support.multidex.MultiDex.install(MultiDex.java:121)
	at com.xxx.xx.app.xx.application.xxxxxx.attachBaseContext(MyApplication.java:212)
	at android.app.Application.attach(Application.java:212)
	at org.robolectric.util.ReflectionHelpers.callInstanceMethod(ReflectionHelpers.java:283)
	at org.robolectric.shadows.ShadowApplication.callAttach(ShadowApplication.java:79)
	at org.robolectric.android.internal.AndroidTestEnvironment.installAndCreateApplication(AndroidTestEnvironment.java:250)
	at org.robolectric.android.internal.AndroidTestEnvironment.setUpApplicationState(AndroidTestEnvironment.java:169)
	at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:301)
	at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:243)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

需要在`build.gradle`中引入

 
    // MultiDex支持
    testImplementation "org.robolectric:shadows-multidex:4.5.1"

例子测试代码:

package com.mobibrw.example;

import org.junit.Test;
import static org.junit.Assert.*;

import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.multidex.ShadowMultiDex;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore("jdk.internal.reflect.*")
@Config(shadows = ShadowMultiDex.class)
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() {
        assertEquals(4, 2 + 2);
    }
}

注意,需要

@Config(shadows = ShadowMultiDex.class)

才能使得配置生效。

如果发生如下错误:

java.lang.VerifyError: Expecting a stackmap frame at branch target 43
Exception Details:
  Location:
    com/meizu/cloud/pushsdk/base/IntentReceiver.onReceive(Landroid/content/Context;Landroid/content/Intent;)V @6: ifne
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: b200 08b6 0013 9a00 25bb 0004 5912 0110
    0x0000010: 0ab7 000e 59b3 000a b600 10bb 0003 59b2
    0x0000020: 000a b600 0fb7 000c b300 09b2 0009 bb00
    0x0000030: 0659 2a2b 2cb7 0011 b600 0d57 b1       


	at java.lang.Class.getDeclaredConstructors0(Native Method)
	at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
	at java.lang.Class.getConstructor0(Class.java:3075)
	at java.lang.Class.getDeclaredConstructor(Class.java:2178)
	at org.robolectric.util.ReflectionHelpers.callConstructor(ReflectionHelpers.java:396)
	at org.robolectric.internal.bytecode.ShadowImpl.newInstanceOf(ShadowImpl.java:18)
	at org.robolectric.shadow.api.Shadow.newInstanceOf(Shadow.java:35)
	at org.robolectric.android.internal.AndroidTestEnvironment.registerBroadcastReceivers(AndroidTestEnvironment.java:541)
	at org.robolectric.android.internal.AndroidTestEnvironment.installAndCreateApplication(AndroidTestEnvironment.java:265)
	at org.robolectric.android.internal.AndroidTestEnvironment.setUpApplicationState(AndroidTestEnvironment.java:169)
	at org.robolectric.RobolectricTestRunner.beforeTest(RobolectricTestRunner.java:301)
	at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:243)
	at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

继续阅读Android Studio 3.6.3/4.0/4.1/4.2配置Robolectric-3.8/4.3.1/4.5.1/4.6.1 Powermock-1.6.6单元测试环境