程序员Java

SpringBoot使用Powermockito单元测试

2020-07-14  本文已影响0人  西敏寺钟声

mockito框架上手非常简单,但是它也有弊端和局限性,不能mock静态方法、私有方法、构造方法等,但powermockito框架很好的弥补了这一缺陷。

版本说明

一般powermockitomockito配合来使用,有相应的版本要求。

powermockito mockito
1.6.5+ 2.0.0-beta - 2.0.42-beta
1.10.19 1.6.4
1.10.8 - 1.10.x 1.6.2+
1.9.5-rc1 - 1.9.5 1.5.0 - 1.5.6
1.9.0-rc1 & 1.9.0 1.4.10 - 1.4.12
1.8.5 1.3.9 - 1.4.9
1.8.4 1.3.7 & 1.3.8
1.8.3 1.3.6
1.8.1 & 1.8.2 1.3.5
1.8 1.3
1.7 1.2.5

pom配置文件

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

mock静态方法

什么时候mock静态方法?比如一个类中有许多的public方法,也有static方法,在static方法中调用static方法,但我们并不想mock静态方法中的任何代码,就需要给这个static方法mock一个返回值,mockito框架就无能为力了,因为它并不能mock静态方法,所以需要配合powermockito框架来使用,如下:

被测试方法

/**
 * mock静态方法 isTrue
 */
@GetMapping(value = "/verifyStaticMcok")
public boolean verifyStaticMcok() {
    String str = "zhangsan";
    boolean flag = isTrue(str);
    log.info("校验姓名:" + flag);
    return flag;
}

/**
 * 静态方法
 *
 * @param userName 用户名不能为空
 */
public static boolean isTrue(String userName) {
    return StringUtils.isNotBlank(userName);
}

测试方法

测试类上加两个注解,@PrepareForTest可以是class数组。

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserSourceController.class)
public class UserSourceControllerTest {
   // ......
}

测试启动前,首先mock出静态方法。

@Before
public void setUp() {
    mockStatic(UserSourceController.class);
    when(UserSourceController.isTrue(any(String.class))).thenReturn(true);
}

正常写测试用例就可以了。

/**
 * mock静态方法
 */
@Test
public void verifyStaticMcok_success() {
    boolean flag = userSourceController.verifyStaticMcok();
    assertTrue(flag);
}

mock私有方法

查了很多资料,网上答案如出一辙,个人感觉private方法不应该被mock,既然是私有的它也属于本类中代码的原有的一部分,那应该让它走完得出结果,但powermock依然可以做到(通过反射)。什么时候使用?跟静态方法的使用场景一样。

被测试方法

/**
 * mock私有方法
 *
 * @param userName 用户名
 */
@GetMapping(value = "/verifyPrivateMethod")
public String verifyPrivateMethod(String userName) {
    log.info("传入的用户名:" + userName);
    String result = getUserName(userName);
    return result;
}

/**
 * 私有方法
 *
 * @param str 传入参数
 */
private String getUserName(String str) {
    log.info("进入了私有方法" + str);
    return str;
}

测试方法

测试类上加两个注解,@PrepareForTest可以是class数组。

@RunWith(PowerMockRunner.class)
@PrepareForTest(UserSourceController.class)
public class UserSourceControllerTest {
   // ......
}

注释写在了代码里。

/**
 * mock私有方法
 */
@Test
public void verifyPrivateMethod_success() throws Exception {
    // spy被测类,只有被spy出来的类,才可以对私有方法进行mock
    UserSourceController spy = PowerMockito.spy(new UserSourceController());
    // 模拟私有方法(反射),意思是传入"zhangsan",强制返回"laozheng"
    // 方法原型: public static <T> OngoingStubbing<T> when(Object instance, String methodName, Object... arguments) throws Exception;
    PowerMockito.when(spy, "getUserName", "zhangsan").thenReturn("laozheng");
    String userName = spy.verifyPrivateMethod("zhangsan");
    // 验证私有方法被执行了
    PowerMockito.verifyPrivate(spy, Mockito.times(1)).invoke("getUserName", "zhangsan");
    assertEquals("laozheng", userName);
}

总结

补充

更新于2020年5月21日

mock HttpServletRequest

@Test
public void integration_test() throws ServiceException {
    MockHttpServletRequest mockHttpServletRequest = new MockHttpServletRequest();
    mockHttpServletRequest.addHeader("password", "123456");
    WalletHRGrantReq walletHRGrantReq = buildWalletHRGrantReq();
    BaseResponse<WalletHRResp> baseResponse = walletHRController.integration_unencrypted(walletHRGrantReq, mockHttpServletRequest);
    verify(walletHRBusiness, times(1)).dealRequest(any(WalletHRGrantReq.class));
    verify(redisLockService, times(1)).lock(any(String.class), any(Long.class), any(Long.class));
    // 实际值#期望值
    assertThat(baseResponse.getCode(), is("200"));
}

更新于2020年7月14日

mock RestTemplate

JSONObject jsonObject = restTemplate.postForObject(processInstanceUrl, httpEntity, JSONObject.class);

类似这种的,可以这样写:

when(restTemplate.postForObject(any(String.class), any(HttpEntity.class), eq(JSONObject.class))).thenReturn(mockJSONObject());
上一篇下一篇

猜你喜欢

热点阅读