Mock静态方法详解
在编写程序的过程中,经常会用到静态方法。静态方法往往是一个固定的函数,可以直接通过类来调用,无需实例化对象。想要测试这类静态方法,却常常很难,因为不同的测试数据能够引起不同的结果。为了解决这个问题,我们就需要使用Mock静态方法来进行测试。下面,我们来详细介绍Mock静态方法的一些方面。
一、Mock静态方法复原
在使用Mock静态方法的时候,有时候我们需要复原某个静态方法的方法体,让它返回真实的结果。这时候我们可以使用PowerMockito.mockStatic
方法,将静态方法mock,然后使用PowerMockito.when()
方法来指定其返回值。下面是使用PowerMockito.mockStatic
方法的示例代码:
public class StaticClass {
public static int staticMethod() {
return 1;
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticClassTest {
@Test
public void testStaticMethod() {
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.when(StaticClass.staticMethod()).thenReturn(2);
Assert.assertEquals(2, StaticClass.staticMethod());
}
}
上述代码中,我们使用了PowerMockito.mockStatic
方法来mock了StaticClass
类的静态方法。然后我们使用PowerMockito.when()
方法指定其返回值为2。最后我们判断其返回值是否为2。因为复原了静态方法的方法体,因此实际上返回的是真实的结果,并不是我们mock的结果。
二、Mock静态方法无返回值
有时候,被测试的静态方法并没有返回值。这时候我们可以使用PowerMockito.doNothing()
方法来指定其无返回值。下面是使用PowerMockito.doNothing()
方法的示例代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticClassTest {
@Test
public void testDoNothingStaticMethod() {
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doNothing().when(StaticClass.class);
StaticClass.staticMethod();
StaticClass.staticMethod();
Assert.assertTrue(true);
}
}
上述代码中,我们使用PowerMockito.doNothing()
方法指定StaticClass
类的静态方法无返回值。然后我们连续调用了两次静态方法,最终判断其返回值是否为true,来验证其无异常。
三、Mock静态方法不生效
有些时候,我们使用Mock静态方法时会出现问题,导致mock并没有生效。这时候,我们需要检查一下是否有以下情况:
- 是否使用了
PowerMockRunner
类作为测试类的运行器; - 是否使用了
PrepareForTest
注解,指定要mock的静态方法所在的类; - 是否添加了对应的Mock库依赖;
- 是否在mock前调用了
PowerMockito.mockStatic
方法; - 是否使用了正确的Mockito/PowerMockito的静态方法。 同时,我们也可以打开PowerMock的调试日志来帮助我们排除问题。下面是开启调试日志的代码:
org.apache.log4j.BasicConfigurator.configure();
Logger.getRootLogger().setLevel(Level.DEBUG);
四、Mock静态方法void
有些时候,我们需要mock带有void返回值的静态方法。在这种情况下,我们需要使用PowerMockito.doNothing()
方法来mock,具体的方法如下示:
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticClassTest {
@Test
public void testStaticMethodWithVoidReturnType() {
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doNothing().when(StaticClass.class);
StaticClass.staticMethodWithVoidReturnType();
Assert.assertTrue(true);
}
}
五、Mock静态方法并发
当一个方法被多次调用时,它可能会获取它所需要的资源并改变其状态,这可能会导致并发问题。在这种情况下,我们需要mock静态方法来控制其并发行为。使用PowerMockito.doAnswer
方法来模拟静态方法的行为。
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticClassTest {
@Test
public void testStaticMethodConcurrency() throws Exception {
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doAnswer(invocation -> {
Thread.sleep(2000);
return 1;
}).when(StaticClass.class);
StaticClass.staticMethod();
Assert.assertTrue(true);
}
}
六、静态方法Mock测试
有时候我们需要测试一个类中的多个静态方法。这时候我们可以使用JUnit的Parameterized
和Mockito的MockitoAnnotations
来进行测试。下面是测试多个静态方法的示例代码:
@RunWith(Parameterized.class)
public class StaticClassTest {
@Mock
private MockedStatic<StaticClass> staticClassMock;
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{1, 10},
{2, 20},
{3, 30}
});
}
@Parameterized.Parameter(0)
public int param1;
@Parameterized.Parameter(1)
public int param2;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testStaticMethods() {
staticClassMock.when(() -> StaticClass.staticMethod1(param1)).thenReturn(param2);
staticClassMock.when(() -> StaticClass.staticMethod2(param1)).thenReturn(param2);
int result1 = StaticClass.staticMethod1(param1);
int result2 = StaticClass.staticMethod2(param1);
Assert.assertEquals(param2, result1);
Assert.assertEquals(param2, result2);
}
}
七、mockup静态方法
在Java 9之前,我们可以使用MockUp
类来mock静态方法。下面是使用MockUp
类来mock静态方法的示例代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticClassTest {
@Test
public void testStaticMethodWithMockUp() {
new MockUp<StaticClass>() {
@Mock
public int staticMethod() {
return 2;
}
};
Assert.assertEquals(2, StaticClass.staticMethod());
}
}
八、Mockito静态方法
Mockito 3.4.0之后新增了Static方法的Mock,可以直接使用Mockito来Mock静态方法。使用Mockito来Mock静态方法只需要按照标准的Mockito的风格来实现即可。下面是使用Mockito来Mock静态方法的示例代码:
@RunWith(MockitoJUnitRunner.class)
public class StaticClassTest {
@Test
public void testStaticMethod() {
Mockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod()).thenReturn(2);
Assert.assertEquals(2, StaticClass.staticMethod());
}
}
九、Mock私有方法
Mock私有方法和Mock静态方法的方式类似,只不过我们需要使用PowerMockito.spy
方法来mock私有方法。下面是使用PowerMockito.spy
来mock私有方法的示例代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticClass.class)
public class StaticClassTest {
@Test
public void testPrivateMethod() throws Exception {
StaticClass sc = PowerMockito.spy(new StaticClass());
PowerMockito.doReturn(2).when(sc, "privateMethod");
Integer result = (Integer) Whitebox.invokeMethod(sc, "privateMethod");
Assert.assertEquals(2, result.intValue());
}
}
十、Mock静态对象选取
当进行静态方法Mock测试时,我们有两种选取静态对象的方式,一种是Mock静态方法所在的类,另一种是Mock静态方法的调用出的对象。我们需要根据测试需要来选择对应的方式。
@RunWith(MockitoJUnitRunner.class)
public class StaticClassTest {
@Test
public void testStaticMethod() {
Mockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod()).thenReturn(2);
// 选取类的方式
Assert.assertEquals(2, StaticClass.staticMethod());
// 选取调用静态方法的实例对象的方式
StaticClass sc = new StaticClass();
Assert.assertEquals(2, sc.staticMethod());
}
}
本篇文章介绍了Mock静态方法的几个方面,包括如何复原静态方法的方法体、Mock静态方法无返回值、Mock静态方法不生效、Mock静态方法void、Mock静态方法并发、静态方法Mock测试、mockup静态方法、Mockito静态方法、Mock私有方法、Mock静态对象选取等等。希望能够对大家使用Mock静态方法提供帮助。