启用Proguard后的UI仪器化测试

11
假设您的应用程序有一个名为Foo的类,并且您在应用程序和测试代码中都使用这个类。但是,该类在应用APK中被混淆后,您的测试代码将无法引用它。是否有可能在使用测试代码的同时继续对该类进行混淆?
以下是一种情况说明:
您的项目具有以下构建文件:
apply plugin: 'com.android.application'
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "ademar.testproguard"
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        resConfigs "en"
    }
    buildTypes {
        all {
            shrinkResources true
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt')
            testProguardFile "proguard-test-rules.pro"
        }
    }
}
dependencies {
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
}

Proguard测试规则:

-dontobfuscate
-dontwarn
-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-ignorewarnings
-keepattributes *Annotation*
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**

清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="ademar.testproguard"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <application
        android:name=".App"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>

App类:

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        new Foo().foo();
    }

}

一个将被混淆的简单类:
public class Foo {

    public void foo() {
        Log.d("TestProguard", "Success called");
    }

}

UI测试:
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {

    @Test
    public void testA() throws Exception {
        Context appContext = InstrumentationRegistry.getTargetContext();
        assertEquals("ademar.testproguard", appContext.getPackageName());
    }

    @Test
    public void testB() throws Exception {
        new Foo().foo();
    }

}

现在如果你运行测试,testA将会通过,注意到App已经被创建了,混淆后的Foo类已经被调用,并且你已经成功记录了Success called的调用。另一方面,testB会收到以下异常:
java.lang.NoClassDefFoundError: Failed resolution of: Lademar/testproguard/Foo;
   at ademar.testproguard.ExampleInstrumentedTest.testB(ExampleInstrumentedTest.java:23)
   at java.lang.reflect.Method.invoke(Native Method)
   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.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
   at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
   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.junit.runners.ParentRunner.run(ParentRunner.java:363)
   at org.junit.runners.Suite.runChild(Suite.java:128)
   at org.junit.runners.Suite.runChild(Suite.java:27)
   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.junit.runners.ParentRunner.run(ParentRunner.java:363)
   at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
   at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
   at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:58)
   at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:375)
   at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2075)
Caused by: java.lang.ClassNotFoundException: Didn't find class "ademar.testproguard.Foo" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/system/framework/android.test.mock.jar", zip file "/data/app/ademar.testproguard.test-yIIGwW8RoqUKvzfKeMd__Q==/base.apk", zip file "/data/app/ademar.testproguard-L6M8bDawepTV9VltDF2TqA==/base.apk"],nativeLibraryDirectories=[/data/app/ademar.testproguard.test-yIIGwW8RoqUKvzfKeMd__Q==/lib/x86, /data/app/ademar.testproguard-L6M8bDawepTV9VltDF2TqA==/lib/x86, /system/lib, /vendor/lib]]
   at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:125)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
   at java.lang.ClassLoader.loadClass(ClassLoader.java:312)

从上面的图片中可以看出,应用程序APK已经对Foo类进行了混淆。

主要apk

Instrumentation类也有Foo,但没有进行混淆:

Instrumentation APK


你能告诉我们最终你做了什么吗? - Islam Salah
3
很抱歉,@IslamSalah,我已经放弃了并关闭了混淆以进行UI测试 :( - ademar111190
1个回答

0
你应该从build.gradle文件中删除'testProguardFile "proguard-test-rules.pro"'。它包含'dontobfuscate',这会有效地禁用测试apk的混淆。
注意:我无法在此时验证这一点。

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