【问题标题】:PowerMock + Robolectric + Dagger2PowerMock + Robolectric + Dagger2
【发布时间】:2016-01-09 04:36:37
【问题描述】:


我测试自定义视图类,其中包含:

  1. android 用户界面元素
  2. 一些逻辑
  3. 静态方法调用
  4. dagger2 依赖项

所以我使用下一个工具进行测试

  1. 用于 UI 元素模拟的 Robolectric
  2. 用于逻辑测试的单元测试
  3. 用于静态方法模拟的 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

【问题讨论】:

  • @MsYvette 这样您就可以看到 ProgressTextView、ProgressTextViewText 和 ProgressTextViewTest 错误。为了以防万一,我离开了其他课程
  • @MsYvette 好的,一切都为你服务;)我删除了额外的代码。现在舒服吗?
  • @MsYvette 谢谢 ;) 你知道我的问题吗?
  • 停止使用 PowerMock :)

标签: android unit-testing robolectric powermock dagger-2


【解决方案1】:
Activity activity;
@Mock
FileDownloaderManager fileDownloaderManager;

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Before
    public void beforeTest() {

        // You intialise activity here
        activity = Robolectric.setupActivity(Activity.class);
    }

    @Test
    public void init_FileDownloaded() {

        // and use it here, the initialisation is out of scope for this
        ProgressTextView progressTextView = new ProgressTextView(activity);
    }

你需要改变你的程序逻辑来允许这样的事情:

Activity activity;
@Mock
FileDownloaderManager fileDownloaderManager;

    activity = Robolectric.setupActivity(Activity.class);

    @Rule
    public PowerMockRule rule = new PowerMockRule();

    @Before
    public void beforeTest() {

    }

    @Test
    public void init_FileDownloaded() {

        ProgressTextView progressTextView = new ProgressTextView(activity);
    }

还有

 ApplicationSIP.get().applicationComponent().inject(this);

我不确定你所说的this

我看不到你在课堂上的 FileDownloaderManager 的首字母缩写,但似乎你正在尝试使用自定义管理器作为内置的 android 管理器。

Caused by: java.lang.ClassCastException: Cannot cast com.tg.osip.tdclient.update_managers.FileDownloaderManager$$EnhancerByMockitoWithCGLIB$$a751cd05 to com.tg.osip.tdclient.update_managers.FileDownloaderManager
at java.lang.Class.cast(Class.java:3369)

我希望这有助于让你更清楚一点。

【讨论】:

  • 我想澄清一下。您建议使用我的 ProgressTextView、ProgressTextViewTest 和您实现的建议(在 ProgressTextViewTest 中替换机器人活动初始化)创建新问题。我说的对吗?
猜你喜欢
  • 2016-04-14
  • 2016-09-25
  • 2012-11-30
  • 2016-07-09
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-05
相关资源
最近更新 更多