我测试自定义视图类,其中包含:
- android 用户界面元素
- 一些逻辑
- 静态方法调用
- dagger2 依赖项
所以我使用下一个工具进行测试
- 用于 UI 元素模拟的 Robolectric
- 用于逻辑测试的单元测试
- 用于静态方法模拟的 PowerMock
Robolectric + PowerMock 集成问题已知且解决方案已知 - https://github.com/robolectric/robolectric/wiki/Using-PowerMock
但是使用此解决方案 dagger2 依赖项失败。
注意代码。
我的自定义视图:
public class ProgressTextView extends TextView {
private String defaultText;
private int fileSize;
private String fileSizeString;
private FileDownloaderI fileDownloader;
@Inject
FileDownloaderManager fileDownloaderManager;
Subscription downloadProgressChannelSubscription;
Subscription downloadCancelChannelSubscription;
public ProgressTextView(Context context) {
super(context);
provideDependency();
}
public ProgressTextView(Context context, AttributeSet attrs) {
super(context, attrs);
provideDependency();
}
public ProgressTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
provideDependency();
}
private void provideDependency() {
ApplicationSIP.get().applicationComponent().inject(this);
}
}
ProgressTextViewTest:
@RunWith(RobolectricUnitTestRunner.class)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
@PrepareForTest(Formatter.class)
公共类 ProgressTextViewTest {
活动活动;
@嘲笑
文件下载管理器文件下载管理器;
@规则
公共 PowerMockRule 规则 = 新 PowerMockRule();
@前
公共无效之前测试(){
// PowerMockito
PowerMockito.mockStatic(Formatter.class);
when(Formatter.formatFileSize(anyObject(), anyInt())).thenReturn("");
// 模拟
MockitoAnnotations.initMocks(this);
// 机器人
活动 = Robolectric.setupActivity(Activity.class);
}
@测试
公共无效init_FileDownloaded(){
ProgressTextView progressTextView = new ProgressTextView(activity);
}
}
In ProgressTextViewTest 错误:
java.lang.NullPointerException
at com.tg.osip.ApplicationSIP.get(ApplicationSIP.java:64)
at com.tg.osip.ui.general.views.ProgressTextView.provideDependency(ProgressTextView.java:56)
at com.tg.osip.ui.general.views.ProgressTextView.<init>(ProgressTextView.java:42)
at com.tg.osip.ui.general.views.ProgressTextViewTest.init_FileDownloaded(ProgressTextViewTest.java:72)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.powermock.modules.junit4.rule.PowerMockStatement$1.run(PowerMockRule.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1873)
at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:773)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:638)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401)
at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:98)
at org.powermock.classloading.ClassloaderExecutor.execute(ClassloaderExecutor.java:78)
at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:49)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
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:152)
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 com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
还有一个麻烦。其他具有 Robolectric 和 dagger2 依赖项的测试不起作用。
ProgressDownloadViewTest_AudioType:
@RunWith(RobolectricUnitTestRunner.class)
公共类 ProgressDownloadViewTest_AudioType {
活动活动;
@嘲笑
文件下载管理器文件下载管理器;
@嘲笑
媒体管理器媒体管理器;
@前
公共无效设置(){
// 模拟
MockitoAnnotations.initMocks(this);
// 机器人
活动 = Robolectric.setupActivity(Activity.class);
}
@测试
公共无效 setDownloadingState_emptyFileDownloaderI() {
ProgressDownloadView progressDownloadView = new ProgressDownloadView(activity, ProgressDownloadView.Type.AUDIO);
...
}
}
例外:
创建模拟代理时发生 ClassCastException :
要模拟的类:'com.tg.osip.tdclient.update_managers.FileDownloaderManager',由类加载器加载:'org.robolectric.internal.bytecode.InstrumentingClassLoader@403f0a22'
创建的类:'com.tg.osip.tdclient.update_managers.FileDownloaderManager$$EnhancerByMockitoWithCGLIB$$a751cd05',由类加载器加载:'org.robolectric.internal.bytecode.InstrumentingClassLoader@403f0a22'
代理实例类:'com.tg.osip.tdclient.update_managers.FileDownloaderManager$$EnhancerByMockitoWithCGLIB$$a751cd05',由类加载器加载:'org.mockito.internal.creation.util.SearchingClassLoader@10bd9df0'
实例创建者:ObjenesisInstantiator
您可能会遇到类加载问题,禁用 Objenesis 缓存 *可能*帮助(请参阅 MockitoConfiguration)
在 org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:61)
在 org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:49)
在 org.powermock.api.mockito.repackaged.CglibMockMaker.createMock(CglibMockMaker.java:24)
在 org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:45)
在 com.tg.osip.ui.general.views.progress_download.ProgressDownloadViewTest_AudioType.setup(ProgressDownloadViewTest_AudioType.java:46)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
在 org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
在 org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
在 org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
在 org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
在 org.junit.runners.ParentRunner.run(ParentRunner.java:363)
在 org.junit.runners.Suite.runChild(Suite.java:128)
在 org.junit.runners.Suite.runChild(Suite.java:27)
在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
在 org.junit.runners.ParentRunner.run(ParentRunner.java:363)
在 org.junit.runner.JUnitCore.run(JUnitCore.java:137)
在 com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
在 com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
在 com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
在 com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
原因:java.lang.ClassCastException:无法将 com.tg.osip.tdclient.update_managers.FileDownloaderManager$$EnhancerByMockitoWithCGLIB$$a751cd05 转换为 com.tg.osip.tdclient.update_managers.FileDownloaderManager
在 java.lang.Class.cast(Class.java:3369)
在 org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:59)
在 org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:49)
在 org.powermock.api.mockito.repackaged.CglibMockMaker.createMock(CglibMockMaker.java:24)
在 org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:45)
在 org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
在 org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
在 org.mockito.Mockito.mock(Mockito.java:1284)
在 org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:33)
在 org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:16)
在 org.mockito.internal.configuration.DefaultAnnotationEngine.createMockFor(DefaultAnnotationEngine.java:43)
在 org.mockito.internal.configuration.DefaultAnnotationEngine.process(DefaultAnnotationEngine.java:66)
在 org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:71)
在 org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:55)
在 org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:108)
... 36 更多
更新
解决在PowerMock + Robolectric + Dagger2. Part I