powerMock和mockito使用


powerMock和mockito

  • powermock和mockito都是做mock的框架,powermock在mockito的基礎上擴展而來,支持mockito的操作(也支持別的mock框架比如easyMock)。因此在maven引入powermock的時候,需要引mockito的包。powermock和mockito版本上要配合着使用。powermock在mockito的基礎上,擴展了對static class, final class,constructor,private method等的mock操作。慎用這些mock,因為在一個良好的設計里,static final private這些class和method是不需要被測試的,會被public方法調用,只要測試public就好。

使用

  • maven引入
<properties>
    <powermock.version>2.0.2</powermock.version>
</properties>
<dependencies>
   <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
   </dependency>
   <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
   </dependency>
</dependencies>
  • 和spring配合使用的時候,要特別注意版本的問題,如果測試起不來的話,先確認下powermock的版本和spring是否對應。

注解

  • @powermockIgnore,默認情況下,powermock試圖使用自己的classLoader去loader所有的class,除里system class(java.lang等目錄下的class),使用powermockIgnore聲明的class,pwoermock也不會加載。

白盒測試

  • powermock提供了幾種方法來處理私有方法,私有變量,私有構造函數
  • Use Whitebox.setInternalState(..) to set a non-public member of an instance or class.
  • Use Whitebox.getInternalState(..) to get a non-public member of an instance or class.
  • Use Whitebox.invokeMethod(..) to invoke a non-public method of an instance or class.
  • Use Whitebox.invokeConstructor(..) to create an instance of a class with a private constructor.

mock構造函數

whenNew(MyClass.class).withNoArguments().thenThrow(new IOException("error message"));

@RunWith(PowerMockRunner.class)
@PrepareForTest(X.class)
public class XTest {
        @Test
        public void test() {
                whenNew(MyClass.class).withNoArguments().thenThrow(new IOException("error message"));

                X x = new X();
                x.y(); // y is the method doing "new MyClass()"

                ..
        }
}
  • prepare的時候,prepareForTest的類是調用MyClass的類。

Delegate to another JUnit Runner

  • spring和powermock結合使用時,使用以下聯合注解
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@PrepareForTest(Test.class)
  • powerMock還是由自己的runner來做object的mock工作,在執行時,再交給delegate的runner去執行。
  • 不同的runner結合使用https://codete.com/blog/testing-spring-boot-application-with-junit-and-different-runners/

各種runner是何時如何起作用的呢

  • 首先runner是干啥的?
    • runner其實就是各個框架在跑測試case的前后處理一些邏輯。
    • 比如在Junit框架中,我們什么都不寫,用Junit默認的Runner BlockJUnit4ClassRunner來執行case,主要做什么事情呢?就是處理Junit框架中的一些注解,比如掃到那些所有@Test的注解,這些是要跑的case,將那些@Ignore的注解的case忽略掉,在執行test case的前后,執行那些@Before和@after的注解的方法。
  • BlockJUnit4ClassRunner
 @Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
        Description description = describeChild(method);
        if (method.getAnnotation(Ignore.class) != null) {
            notifier.fireTestIgnored(description);
        } else {
            runLeaf(methodBlock(method), description, notifier);
        }
    }

    @Override
    protected Description describeChild(FrameworkMethod method) {
        return Description.createTestDescription(getTestClass().getJavaClass(),
                testName(method), method.getAnnotations());
    }

    @Override
    protected List<FrameworkMethod> getChildren() {
        return computeTestMethods();
    }
  • 主要是這三個方法,getChildren得到所有@Test注解的方法。runChild中,將要調用的方法組織好,最后通過反射調用這個方法執行,同時處理執行成功或者執行失敗的結果。

  • mockito的runner,JUnit44RunnerImpl,在跑test之前,將@Mock注解的對象構造出來。

  • SpringJUnit4ClassRunner 在test class中做依賴注入。

  • 總之,就是各個不同的runner在處理各自框架的職責。mockitorunner的就是負責mock,spring的runner就是負責依賴注入。

  • 這里也就解釋了powermock的delegate是如何work的: testClass首先會交給powermockRunner完成自己的mock的工作,然后再交給springRunner去完成依賴注入的工作。

  • https://dzone.com/articles/understanding-junits-runner

  • https://codete.com/blog/testing-spring-boot-application-with-junit-and-different-runners/

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM