写在前面
最近接手了一个新项目,在熟悉业务的阶段需要调试代码中的单元测试,也需要补充相关的测试类;用到的测试工具主要有 PowerMockito junit Mockito
,今天就浅析一下相关的用法。
PowerMock 是一个扩展其他mock类库(EasyMock、mocktito) 的框架。PowerMock 通过定制的类加载器、字节码等操作来实现对静态方法、构造方法、私有方法, Final 方法和 Final 类的模拟支持。PowerMock致力于使用少量方法和注解来扩展现有API以实现额外的功能。目前,PowerMock 仅支持 EasyMock 和 Mockito。PowerMock 让你以普通的方式对待不可测试的代码做单元测试。
正文开始
由于接手的项目比较复杂,项目启动时间比较长,不利于调试。所以就新建一个 Spring Boot的项目用于研究单元测试。
项目准备
- Spring Boot 搭建
Idea 配合官方的脚手架快速搭建 Spring Boot web 项目。
注意事项:
start.spring.io/ 这网站可能无法访问,或者在 Idea 创建的时候出现错误。 解决方式:
- 自己搭个梯子,在Idea中配置代理
- 替换网址为 start.aliyun.com/
- 找个别人下载好的初始化的工程在Idea中导入
- 初始化需要测试的代码
@Service
public class AppServiceImp implements AppService {
@Override
public String getApp(String name) {
System.out.println("Get app method");
return null;
}
@Override
public String updateApp() {
System.out.println("Update app method");
return null;
}
@Override
public String checkApp() {
System.out.println("Check app method");
return null;
}
}
复制代码
@Service
public class UserServiceImp implements UserService{
@Override
public String getUser(String name) {
System.out.println("Get method");
return name;
}
@Override
public String updateUser() {
String res = checkUser();
if (res.equals("ok")) {
System.out.println("Update check method");
return "bob";
}
System.out.println("Update method");
return "andy";
}
@Override
public String checkUser() {
System.out.println("check method");
return "ok";
}
}
复制代码
- 配置 Maven
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.18.0</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0-beta.5</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0-beta.5</version>
</dependency>
复制代码
注意事项:
如果配置的包版本不正确的时候会出现以下几个错误:
-
java.lang.NullPointerException at org.powermock.api.mockito.internal.expectation
-
java.lang.IllegalStateException: Failed to load ApplicationContext
-
Compile failed because of "Incompatible types. Found: 'java.lang.Class<org.robolectric.RobolectricTestRunner>', required: 'java.lang.Class<? extends org.junit.runner.Runner>'
-> 解决方案
前两者的解决方案基本都是版本的问题,特别需要注意 junit 的版本需要 大于 4.4;然后 powermock 的版本需要与 junit 的版本相对应。
代码演示
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = WinterApplication.class)
public class UserTest {
@SpyBean
private UserService userService;
@MockBean
private AppService appService;
@Test
public void spyUser() {
String user = "bob";
// SpyBean 相当于 Autowired
Assert.assertEquals(user, userService.getUser(user));
}
@Test
public void spyUser1() {
String user = "bob";
// 运行方法并覆盖返回值
PowerMockito.when(userService.checkUser()).thenReturn("ok");
assertThat(userService.updateUser(), equalTo(user));
}
@Test
public void spyUser2() {
String user = "bob";
// 不运行方法直接设置返回值
PowerMockito.doReturn("ok").when(userService).checkUser();
assertThat(userService.updateUser(), equalTo(user));
}
@Test
public void mockApp1() {
String app = "chrome";
// MockBean 默认返回值 为null
assertThat(appService.getApp(app), equalTo(app));
}
@Test
public void mockApp2() {
String app = "chrome";
// MockBean 默认返回值 修改为 chrome
PowerMockito.when(appService.getApp(Mockito.any())).thenReturn(app);
assertThat(appService.getApp(app), equalTo(app));
}
}
复制代码
应用场景 MockBean 可以跳过业务中不需要执行的所有方法,需要注意的是有用到返回值的可以构造返回值;SpyBean 可以执行业务逻辑,并对部分方法设置跳过并构造的返回值。
注意事项:
-
MockBean
默认不执行,默认返回null;可以通过PowerMockito.when(userService.getUser(Mockito.any())).thenReturn("bob");
的方式覆盖返回值; -
SpyBean
默认会调用真实的方法,有返回值的返回真实的返回值;可以通过PowerMockito.doReturn("ok").when(userService).checkUser()
的方式 mock 不执行并覆盖返回值; -
MockBean
与SpyBean
的作用类似Autowired
只不过会被 Mock特殊处理。
近期评论