Android Studio
提供了比较方便的单元测试,但是由于Android
系统的限制(Classloader
是Google
自己实现的,Powermock
无法修改底层的bytecode
),目前Powermock
还没办法直接在设备上执行测试,但是我们代码中难免存在一些静态对象,需要测试的时候,只能求助于Powermock
与Robolectric
的组合。
具体的配置如下:
1.首先在需要测试的项目的build.gradle
中声明需要使用Powermock
与Robolectric
。
testCompile 'junit:junit:4.12' testCompile 'org.powermock:powermock-api-mockito:1.6.5' testCompile 'org.powermock:powermock-module-junit4-rule:1.6.5' testCompile 'org.powermock:powermock-module-junit4:1.6.5' testCompile "org.powermock:powermock-classloading-xstream:1.6.5" /*不可使用3.1.x版本,3.1.x版本无法与PowerMock配合测试,运行时候直接报错*/ testCompile 'org.robolectric:robolectric:3.0'
2.定义测试基类,在基类中声明一些必备的设置
AbsRobolectricPowerMockTest.java
import android.os.Build; import org.junit.Rule; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunnerDelegate; import org.powermock.modules.junit4.rule.PowerMockRule; import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.annotation.Config; /** * Created by longsky.wq on 2016/8/22. */ @PowerMockRunnerDelegate(RobolectricGradleTestRunner.class) @RunWith(PowerMockRunner.class) @Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.JELLY_BEAN_MR1) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*","javax.crypto.","java.security.*"}) abstract public class AbsRobolectricPowerMockTest { @Rule public PowerMockRule rule = new PowerMockRule(); }
3.定义真正的测试子类
DeckardActivityTest.java
import org.junit.Test; import org.junit.Assert; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import static junit.framework.Assert.assertTrue; @PrepareForTest(Static.class) public class DeckardActivityTest extends AbsRobolectricPowerMockTest { @Test public void testStaticMocking() { /*如果如下断言失败,说明Robolectric环境没有初始化成功,说明配置存在问题*/ Assert.assertNotNull(RuntimeEnvironment.application); PowerMockito.mockStatic(Static.class); Mockito.when(Static.staticMethod()).thenReturn("hello mock"); assertTrue(Static.staticMethod().equals("hello mock")); } }
注意,参考链接中的内容不可完全相信,按照参考链接中的配置(Robolectric-3.1.2
+PowerMock-1.6.5
),一般会遇到如下问题(看上去很怪异,其实是由于不同的classloader
同时加载了相同的类,导致尽管类名是相同的,但是依旧无法进行类型转换):
com.thoughtworks.xstream.converters.ConversionException: Could not call org.apache.tools.ant.Project$AntRefTable.readObject() : Cannot convert type org.apache.tools.ant.Project to type org.apache.tools.ant.Project ---- Debugging information ---- class : org.apache.tools.ant.types.FileSet required-type : org.apache.tools.ant.types.FileSet converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter path : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/this$1/outer-class/dependencyResolver/dependencyResolver/project/references/hashtable/org.apache.tools.ant.types.FileSet/project line number : 167 ------------------------------- message : Could not call org.apache.tools.ant.Project$AntRefTable.readObject() cause-exception : com.thoughtworks.xstream.converters.ConversionException cause-message : Cannot convert type org.apache.tools.ant.Project to type org.apache.tools.ant.Project class : org.apache.tools.ant.Project$AntRefTable required-type : org.apache.tools.ant.types.FileSet converter-type : com.thoughtworks.xstream.converters.reflection.SerializableConverter path : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/this$1/outer-class/dependencyResolver/dependencyResolver/project/references/hashtable/org.apache.tools.ant.types.FileSet/project line number : 167 class[1] : org.apache.tools.ant.Project converter-type[1] : com.thoughtworks.xstream.converters.reflection.ReflectionConverter class[2] : org.robolectric.internal.dependency.MavenDependencyResolver class[3] : org.robolectric.internal.dependency.CachedDependencyResolver class[4] : org.robolectric.RobolectricGradleTestRunner class[5] : org.robolectric.RobolectricTestRunner$HelperTestRunner class[6] : org.robolectric.RobolectricTestRunner$HelperTestRunner$1 class[7] : org.powermock.modules.junit4.rule.PowerMockStatement class[8] : org.powermock.modules.junit4.rule.PowerMockStatement$1 version : not available ------------------------------- at com.thoughtworks.xstream.core.util.SerializationMembers.callReadObject(SerializationMembers.java:133) at com.thoughtworks.xstream.converters.reflection.SerializableConverter.doUnmarshal(SerializableConverter.java:455) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:480) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:412) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1206) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1190) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1061) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1052) at org.powermock.classloading.DeepCloner.clone(DeepCloner.java:54) at org.powermock.classloading.AbstractClassloaderExecutor.executeWithClassLoader(AbstractClassloaderExecutor.java:56) at org.powermock.classloading.SingleClassloaderExecutor.execute(SingleClassloaderExecutor.java:67) at org.powermock.classloading.AbstractClassloaderExecutor.execute(AbstractClassloaderExecutor.java:43) at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:75) at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:250) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:176) at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:49) 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.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:142) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:148) at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:140) at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.withContextClassLoader(DelegatingPowerMockRunner.java:131) at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.run(DelegatingPowerMockRunner.java:140) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121) at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) Caused by: com.thoughtworks.xstream.converters.ConversionException: Cannot convert type org.apache.tools.ant.Project to type org.apache.tools.ant.Project ---- Debugging information ---- class : org.apache.tools.ant.types.FileSet required-type : org.apache.tools.ant.types.FileSet converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter path : /org.powermock.modules.junit4.rule.PowerMockStatement$1/outer-class/fNext/this$1/outer-class/dependencyResolver/dependencyResolver/project/references/hashtable/org.apache.tools.ant.types.FileSet/project line number : 167 ------------------------------- at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:439) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:263) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.reflection.SerializableConverter$2.readFromStream(SerializableConverter.java:337) at com.thoughtworks.xstream.core.util.CustomObjectInputStream.readObjectOverride(CustomObjectInputStream.java:120) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364) at java.util.Hashtable.readObject(Hashtable.java:996) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.thoughtworks.xstream.core.util.SerializationMembers.callReadObject(SerializationMembers.java:125) ... 86 more