PowerMock + Robolectric + Dagger2

时间:2016-01-09 04:36:37

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


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

  1. android ui elements
  2. 一些逻辑
  3. 静态方法调用
  4. dagger2依赖
  5. 所以我使用下一个工具进行测试

    1. 用于UI元素的Robolectric嘲笑
    2. 逻辑测试的单元测试
    3. 用于静态方法模拟的PowerMock
    4. 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)
      public class ProgressTextViewTest {
      
          Activity activity;
          @Mock
          FileDownloaderManager fileDownloaderManager;
      
              @Rule
              public PowerMockRule rule = new PowerMockRule();
      
              @Before
              public void beforeTest() {
                  // PowerMockito
                  PowerMockito.mockStatic(Formatter.class);
                  when(Formatter.formatFileSize(anyObject(), anyInt())).thenReturn("");
                  // Mockito
                  MockitoAnnotations.initMocks(this);
                  // Robolectic
                  activity = Robolectric.setupActivity(Activity.class);
              }
      
              @Test
              public void 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)
      public class ProgressDownloadViewTest_AudioType {
      
          Activity activity;
          @Mock
          FileDownloaderManager fileDownloaderManager;
          @Mock
          MediaManager mediaManager;
      
              @Before
              public void setup() {
                  // Mockito
                  MockitoAnnotations.initMocks(this);
                  // Robolectic
                  activity = Robolectric.setupActivity(Activity.class);
              }
      
              @Test
              public void setDownloadingState_emptyFileDownloaderI() {
                  ProgressDownloadView progressDownloadView = new ProgressDownloadView(activity, ProgressDownloadView.Type.AUDIO);
                  ...
              }
      
      }
      

      例外:

          ClassCastException occurred while creating the mockito proxy :
        class to mock : 'com.tg.osip.tdclient.update_managers.FileDownloaderManager', loaded by classloader : 'org.robolectric.internal.bytecode.InstrumentingClassLoader@403f0a22'
        created class : 'com.tg.osip.tdclient.update_managers.FileDownloaderManager$$EnhancerByMockitoWithCGLIB$$a751cd05', loaded by classloader : 'org.robolectric.internal.bytecode.InstrumentingClassLoader@403f0a22'
        proxy instance class : 'com.tg.osip.tdclient.update_managers.FileDownloaderManager$$EnhancerByMockitoWithCGLIB$$a751cd05', loaded by classloader : 'org.mockito.internal.creation.util.SearchingClassLoader@10bd9df0'
        instance creation by : ObjenesisInstantiator
      
      You might experience classloading issues, disabling the Objenesis cache *might* help (see MockitoConfiguration)
          at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:61)
          at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:49)
          at org.powermock.api.mockito.repackaged.CglibMockMaker.createMock(CglibMockMaker.java:24)
          at org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:45)
          at com.tg.osip.ui.general.views.progress_download.ProgressDownloadViewTest_AudioType.setup(ProgressDownloadViewTest_AudioType.java:46)
          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.RunBefores.evaluate(RunBefores.java:24)
          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)
      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)
          at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:59)
          at org.powermock.api.mockito.repackaged.ClassImposterizer.imposterise(ClassImposterizer.java:49)
          at org.powermock.api.mockito.repackaged.CglibMockMaker.createMock(CglibMockMaker.java:24)
          at org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:45)
          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:1284)
          at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:33)
          at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:16)
          at org.mockito.internal.configuration.DefaultAnnotationEngine.createMockFor(DefaultAnnotationEngine.java:43)
          at org.mockito.internal.configuration.DefaultAnnotationEngine.process(DefaultAnnotationEngine.java:66)
          at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:71)
          at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:55)
          at org.mockito.MockitoAnnotations.initMocks(MockitoAnnotations.java:108)
          ... 36 more
      
      

      更新
      解析PowerMock + Robolectric + Dagger2. Part I

1 个答案:

答案 0 :(得分:0)

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

我无法在您的课程中看到您在初始化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) 的位置,但您似乎正在尝试将自定义管理器用作内置的Android管理器。

{{1}}

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