Android真机使用Mockito-1.10.19+Dexmaker-1.2在Mock仅包内可见类时报告错误“java.lang.UnsupportedOperationException: cannot proxy inaccessible class ***”

Android真机使用Mockito-1.10.19+Dexmaker-1.2Mock仅包内可见类时报告如下错误:

java.lang.UnsupportedOperationException: cannot proxy inaccessible class class com.yunos.tv.shake.biz.PackageAccessible
at com.android.dx.stock.ProxyBuilder.buildProxyClass(ProxyBuilder.java:269)
at com.android.dx.mockito.DexmakerMockMaker.createMock(DexmakerMockMaker.java:56)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
at org.mockito.Mockito.mock(Mockito.java:1285)
at org.mockito.Mockito.mock(Mockito.java:1163)
at com.yunos.tv.shake.biz.PackageAccessibleTest.setUp(PackageAccessibleTest.java:17)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1853)
Caused by: java.lang.IllegalAccessError: Class com.yunos.tv.shake.biz.PackageAccessible extended by class PackageAccessible_Proxy is inaccessible (declaration of 'PackageAccessible_Proxy' appears in /data/data/com.yunos.tv.shake.biz.test/cache/Generated_179875952.jar)
at dalvik.system.DexFile.defineClassNative(Native Method)
at dalvik.system.DexFile.defineClass(DexFile.java:226)
at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:219)
at dalvik.system.DexPathList.findClass(DexPathList.java:321)
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at com.android.dx.stock.ProxyBuilder.loadClass(ProxyBuilder.java:284)
at com.android.dx.stock.ProxyBuilder.buildProxyClass(ProxyBuilder.java:266)
... 15 more

被测试类代码如下:

package com.yunos.tv.shake.biz;

class PackageAccessible {
}

注意上述被测试类前面没有声明public,因此默认是default访问,也就是包内可见。我们下面的测试代码跟被测试类属于同一个包名package com.yunos.tv.shake.biz,因此,按理说,是可以正常访问的。
测试类的代码如下:

package com.yunos.tv.shake.biz;

import android.test.AndroidTestCase;

import org.mockito.Mockito;

public class PackageAccessibleTest extends AndroidTestCase {
    protected void setUp() throws Exception {
        super.setUp();
        /*解决BUG dexcache == null (and no default could be found; consider setting the 'dexmaker.dexcache' system pr*/
        System.setProperty(
                "dexmaker.dexcache",
                getContext().getCacheDir().getPath());
        PackageAccessible packageAccessible = Mockito.mock(PackageAccessible.class);
    }
}

这个问题只在ART虚拟机下面发生异常,相同的代码在Dalvik下面是完全正常的。
问题发生的原因暂时还不能确定,应该是ART虚拟机实现功能的时候的不兼容导致的。
解决方法为在测试代码中声明一个继承被测试类的子类,并且把子类声明成public
如下:

package com.yunos.tv.shake.biz;

public class PackageAccessibleShadow extends PackageAccessible {
}

修改后的测试代码如下:

package com.yunos.tv.shake.biz;

import android.test.AndroidTestCase;

import org.mockito.Mockito;

public class PackageAccessibleTest extends AndroidTestCase {
    protected void setUp() throws Exception {
        super.setUp();
        /*解决BUG dexcache == null (and no default could be found; consider setting the 'dexmaker.dexcache' system pr*/
        System.setProperty(
                "dexmaker.dexcache",
                getContext().getCacheDir().getPath());
        PackageAccessibleShadow packageAccessible = Mockito.mock(PackageAccessibleShadow.class);
    }
}

即可解决上述问题。

发布者

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注