Java测试框架系列:PowerMock使用系列-7:和Mockito一起使用PowerMock

2,825 阅读6分钟

和Mockito一起使用PowerMock

内容

  1. 介绍
  2. 支持版本
  3. Maven配置
  4. 用法
    1. Mock静态方法
      1. 验证行为
      2. 参数匹配器
      3. 验证准确的调用次数
      4. 存根(打桩)静态方法来引发异常
      5. Mock,存根和验证静态方法的完整示例
    2. 部分Mock
      1. 验证行为(方法是否被调用)
      2. 验证私有(方法)行为
      3. Mock新对象的构造
      4. 验证新对象的构造
      5. 使用参数匹配器
      6. Spying
      7. 部分mock私有方法
  5. Mockito Inline Mock Maker
  6. 更多信息
  7. Mockito 1.7

介绍

事实上,PowerMock提供了一个名为“PowerMockito”的类,用于创建mock对象/类并开始验证和期望(一个行为/调用或者返回值),您仍然可以使用Mockito设置和验证期望的所有其他内容(例如times(),anyInt())。

所有的用法需要@RunWith(PowerMockRunner.class),并在类上标识@PrepareForTest注解。

支持版本

PowerMock 2.0.0及更高版本具有Mockito 2的支持。

PowerMock 1.7.0及更高版本具有Mockito 2的实验性支持。

许多问题仍未解决。PowerMock使用Mockito 内部API,但至少可以同时使用两个模拟框架。

MockitoPowerMock
2.8.9+2.x
2.8.0-2.8.91.7.x
2.7.51.7.0RC4
2.4.01.7.0RC2
2.0.0-beta - 2.0.42-beta1.6.5-1.7.0RC
1.10.8 - 1.10.x1.6.2 - 2.0
1.9.5-rc1 - 1.9.51.5.0 - 1.5.6
1.9.0-rc1 & 1.9.01.4.10 - 1.4.12
1.8.51.3.9 - 1.4.9
1.8.41.3.7 & 1.3.8
1.8.31.3.6
1.8.1 & 1.8.21.3.5
1.8 1.3
1.7 1.2.5

Maven配置

JUnit

TestNG

用法

在下面的示例中,为了更好地了解方法的位置,我们在Mockito或PowerMockito API中未对方法使用静态导入。但是,我们强烈建议您在实际的测试用例中静态导入方法,以提高可读性。

注意:Mockito团队在Mockito 2.1.0中增加了模拟final类/方法的能力。自PowerMock 1.7.0(经过Mockito 2.8.9测试)以来,PowerMock支持此功能。可以使用PowerMock Configuration启用该功能。如果使用Mockito 2,建议使用Mockito模拟final方法/类。

Mock静态方法

如何模拟(mock)和存根(stub):

  1. 在类上添加 @PrepareForTest
@PrepareForTest(Static.class) // Static.class contains static methods
  1. 调用PowerMockito.mockStatic()以Mock静态类(用PowerMockito.spy(class)mock特定方法):
PowerMockito.mockStatic(Static.class);
  1. 只需使用Mockito.when()来设置您的期望:
Mockito.when(Static.firstStaticMethod(param)).thenReturn(value);

注意:如果需要模拟java系统类加载器/bootstrap类加载器(在java.lang或java.net等中定义的类)加载的类,则需要使用方法。

如何验证行为

静态方法的验证分两个步骤进行。

  1. 首先调用PowerMockito.verifyStatic(Static.class) 以开始验证行为,然后
  2. 调用的静态方法Static.class进行验证。例如:
PowerMockito.verifyStatic(Static.class); // 1
Static.firstStaticMethod(param); // 2

重要提示:您需要按方法逐个调用verifyStatic(Static.class)验证。

如何使用参数匹配器

Mockito匹配器可能仍适用于PowerMock mock。例如,对每个mock的静态方法使用自定义参数匹配器:

PowerMockito.verifyStatic(Static.class);
Static.thirdStaticMethod(Mockito.anyInt());

如何验证确切的调用次数

您仍然可以将Mockito.VerificationMode(例如Mockito.times(x))与PowerMockito.verifyStatic(Static.class, Mockito.times(2))结合使用:

PowerMockito.verifyStatic(Static.class, Mockito.times(1));

如何将静态void方法存根以引发异常

如果不是私有方法:

PowerMockito.doThrow(new ArrayStoreException("Mock error")).when(StaticService.class);
StaticService.executeMethod();

请注意,您可以对final类/final方法执行相同的操作:

PowerMockito.doThrow(new ArrayStoreException("Mock error")).when(myFinalMock).myFinalMethod();

对于私有方法,请使用PowerMockito.when,例如:

when(tested, "methodToExpect", argument).thenReturn(myReturnValue);

Mock,存根和验证静态方法的完整示例

@RunWith(PowerMockRunner.class)
@PrepareForTest(Static.class)
public class YourTestCase {
    @Test
    public void testMethodThatCallsStaticMethod() {
        // mock all the static methods in a class called "Static"
        PowerMockito.mockStatic(Static.class);
        // use Mockito to set up your expectation
        Mockito.when(Static.firstStaticMethod(param)).thenReturn(value);
        Mockito.when(Static.secondStaticMethod()).thenReturn(123);

        // execute your test
        classCallStaticMethodObj.execute();

        // Different from Mockito, always use PowerMockito.verifyStatic(Class) first
        // to start verifying behavior
        PowerMockito.verifyStatic(Static.class, Mockito.times(2));
        // IMPORTANT:  Call the static method you want to verify
        Static.firstStaticMethod(param);


        // IMPORTANT: You need to call verifyStatic(Class) per method verification,
        // so call verifyStatic(Class) again
        PowerMockito.verifyStatic(Static.class); // default times is once
        // Again call the static method which is being verified
        Static.secondStaticMethod();

        // Again, remember to call verifyStatic(Class)
        PowerMockito.verifyStatic(Static.class, Mockito.never());
        // And again call the static method.
        Static.thirdStaticMethod();
    }
}

部分Mock

您可以通过使用PowerMockito的PowerMockito.spy部分mock方法。请注意(以下内容取自Mockito文档,同样适用于PowerMockito):有时,无法使用标准when(..)方法对spy()进行打桩(stubbing,存根)。例如:

List list = new LinkedList();
List spy = spy(list);
//这样是不行的:真正的方法spy.get(0)会被调用并抛出IndexOutOfBoundsException异常(这个list仍然是空的)
//when(spy.get(0)).thenReturn("foo");

//你需要用 doReturn() 去打桩
doReturn("foo").when(spy).get(0);

如何验证行为

只需使用Mockito.vertify()进行标准验证:

Mockito.verify(mockObj, times(2)).methodToMock();

如何验证private行为

使用PowerMockito.verifyPrivate(),例如

verifyPrivate(tested).invoke("privateMethodName", argument1);

这也适用于私有静态方法。

如何mock新对象的构造

使用PowerMockito.whenNew,例如

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

请注意,您必须准备在测试过程中的用于创建MyClass新实例中的类,而不是其MyClass本身。例如,如果正在执行的类称为X,则必须先进行操作@PrepareForTest(X.class)才能使whenNew工作:

@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()"

      	..
    }
}

如何验证新对象的构造

使用PowerMockito.verifyNew,例如

verifyNew(MyClass.class).withNoArguments();

如何使用参数匹配器

如何使用参数匹配器mock:

Mockito.verify(mockObj).methodToMock(Mockito.anyInt());  

Spy的完整示例

@RunWith(PowerMockRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
@PrepareForTest(PartialMockClass.class)
public class YourTestCase {
    @Test
    public void spyingWithPowerMock() {        
        PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass());

        // use Mockito to set up your expectation
        Mockito.when(classUnderTest.methodToMock()).thenReturn(value);

        // execute your test
        classUnderTest.execute();

        // Use Mockito.verify() to verify result
        Mockito.verify(mockObj, times(2)).methodToMock();
    }
}

私有方法部分mock的完整示例

(在PowerMock版本1.3.6+中可用)

@RunWith(PowerMockRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
@PrepareForTest(PartialMockClass.class)
public class YourTestCase {
    @Test
    public void privatePartialMockingWithPowerMock() {        
        PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass());

        // use PowerMockito to set up your expectation
        PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1");

        // execute your test
        classUnderTest.execute();

        // Use PowerMockito.verify() to verify result
        PowerMockito.verifyPrivate(classUnderTest, times(2)).invoke("methodToMock", "parameter1");
    }
}

Mockito mock-maker-inline

在PowerMock版本1.7.0中可用

Mockito团队在Mockito 2.1.0中增加了对final类/方法进行mock的支持。通过在src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker中添加包含以下一行的文件,可以在PowerMock中启用此功能 :

mock-maker-inline

PowerMock实现了自己的MockMaker,这导致与Mockito的mock-maker-inline不兼容,即使PowerMock只是作为依赖添加而未使用。如果在类路径中存在两个org.mockito.plugins.MockMaker,则只能使用其中一个,但不确定是哪一个。

但是PowerMock可以将调用委托给另一个MockMaker,因此无需PowerMock即可运行测试。从PowerMock 1.7.0开始,可以使用PowerMock Configuration进行配置

MockMaker可以通过创建org/powermock/extensions/configuration.properties文件来配置和设置:

mockito.mock-maker-class=mock-maker-inline

将Mockitomock-maker-inline与PowerMock结合使用的示例: github.com/powermock/p…

更多信息

请查看GitHub中的示例源码。也可以参考在Jayway团队博客中PowerMockito的相关博客