一、背景
- 在日常开发编码中,经常会遇到这样的场景:开发接口的过程中,有部分数据依赖同事开发的接口,需要等到同事的接口开发完成以后,才能开始我们的功能开发。这样依赖同事,有时候会影响到项目的上线节奏,所以我们在寻找有没能够解决这种场景的工具。
- 或者说,我们在分析完业务需求后,设计验证大的业务流程的代码的时候,也可以用到此类工具。首先把整体的大的处理逻辑完成,把细枝末节的处理打上标记 ToDo。
- Mockito 可以帮助我们在编写单元测试类的时候,调用指定接口返回指定的数据信息。通过模拟数据,替代真实数据,这样我们不需要等到同事的接口开发完成后,再开始我们的工作,做到“并行开发”。
二、实施过程
1. 引入依赖
<!-- 引入mockito 依赖 -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
2. CURD Spring MVC 业务代码(略)
3. 基于 Mockito 的单元测试基类
- 一般使用项目中已经写好的测试基类即可。
@RunWith(SpringJUnit4ClassRunner.class)//表示整合JUnit4进行测试
@ContextConfiguration(locations={
"classpath:spring/applicationContext.xml",
"classpath:spring/applicationContext-persistent.xml"})//加载spring配置文件
public class BaseSpringTest {
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
/**
* 控制台打印展示对象 Json 字符串信息
*/
public void printlnJson(Object object) {
System.out.println(gson.toJson(object));
}
@Autowired
private UserService userService;
/**
* 设置上下文登录用户数据
*/
public LoginUser mockLoginUser(String userId){
LoginUser loginUser = new LoginUser();
UserBaseV userBaseV = userService.queryOne(userId);
User user = new User();
BeanUtil.copyProperties(user, userBaseV);
// 绑定指定用户
UserUtil.currentUser.set(user);
PreconditionsUtil.checkNotNull(userBaseV, "查询失败, 未查询到对应的用户数据");
loginUser.setId(userBaseV.getId());
loginUser.setLoginName(userBaseV.getUsername());
loginUser.setDealerId(userBaseV.getDealerId());
loginUser.setOrgId(userBaseV.getOrganizationId());
loginUser.setUserName(userBaseV.getName());
return loginUser;
}
}
4. Service 对应的 Mockito 测试类
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* demo
*/
public class MockitoBusinessTypeTest extends BaseMockitoSpringTest {
@InjectMocks
private BusinessTypeService businessTypeService = mock(BusinessTypeService.class);
@Mock
private IvrDealerSettingService ivrDealerSettingService;
/**
* 上边使用 InjectMocks 注释的类,里面如果有依赖到的 service 可以通过下面的方法,
* Mock 注解,会自动为上边那个类注入下面这个service
*/
@Mock
private LOVService lovService;
@Autowired
private SeatService seatService;
@Before
public void initMock(){
MockitoAnnotations.initMocks(this);
doReturn(Lists.newArrayList()).when(businessTypeService).getSatisfactionBusinessType();
doReturn("hello world").when(ivrDealerSettingService).getSkillGroupByDealerAndIvrKey("a", "b", "c");
BusinessTypeV businessTypeResult = new BusinessTypeV();
businessTypeResult.setCode("11");
doReturn(businessTypeResult).when(businessTypeService).getUserDefaultBusinessType("system");
}
@Test
public void queryTest(){
List<BusinessTypeLOV> list = businessTypeService.getSatisfactionBusinessType();
String ivrResult = ivrDealerSettingService.getSkillGroupByDealerAndIvrKey("a", "b", "c");
System.out.println(new Gson().toJson(list));
System.out.println(ivrResult);
}
/**
* mock with autowired
*/
@Test
public void seatQueryTest(){
String businessType = businessTypeService.getUserDefaultBusinessType("system").getCode();
// 结果是可以正常执行的
printlnJson(seatService.selectByBusinessType(businessType));
}
}
5. Controller 对应的 Mockito 测试类
/**
* Controller 测试类
*/
@RunWith(MockitoJUnitRunner.class)
public class MockitoBusinessTypeControllerTest {
private MockMvc mockMvc;
@InjectMocks
private BusinessTypeController businessTypeController;
@Mock
private BusinessTypeService businessTypeService;
@Mock
private ClusterMessageListener clusterMessageListener;
@Before
public void initMock() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(businessTypeController).build();
}
@Test
public void getBusinessInfoTest() throws Exception {
// mock Service 方法行为
BusinessTypeV entity = new BusinessTypeV();
entity.setCode("11");
when(businessTypeService.queryOne(Mockito.any())).thenReturn(entity);
// 模拟接口调用
mockMvc.perform(get("/rest/businessType/all/getBusinessInfo")
.param("businessType", "11")
)
.andDo(print())
.andExpect(status().isOk());
}
}
6. 注解的说明
首先是Spring的几个Annotate:
- RunWith(SpringJUnit4ClassRunner.class): 表示使用Spring Test组件进行单元测试;
- WebAppConfiguration: 使用这个Annotate会在跑单元测试的时候真实的启一个web服务,然后开始调用Controller的Rest API,待单元测试跑完之后再将web服务停掉;
- ContextConfiguration: 指定Bean的配置文件信息,可以有多种方式,这个例子使用的是文件路径形式,如果有多个配置文件,可以将括号中的信息配置为一个字符串数组来表示;
然后是Mockito的Annotate:
- Mock: 如果该对象需要mock,则加上此Annotate;
- InjectMocks: 使mock对象的使用类可以注入mock对象,在上面这个例子中,mock对象是UserService,使用了UserService的是UserController,所以在Controller加上该Annotate;
Setup方法:
- MockitoAnnotations.initMocks(this): 将打上Mockito标签的对象起作用,使得Mock的类被Mock,使用了Mock对象的类自动与Mock对象关联。
- mockMvc: 细心的朋友应该注意到了这个对象,这个对象是Controller单元测试的关键,它的初始化也是在setup方法里面。
测试用例:
- mockMvc.perform: 发起一个http请求。
- post(url): 表示一个post请求,url对应的是Controller中被测方法的Rest url。
- param(key, value): 表示一个request parameter,方法参数是key和value。
- andDo(print()): 表示打印出request和response的详细信息,便于调试。
- andExpect(status().isOk()): 表示期望返回的Response Status是200。
- andExpect(content().string(is(expectstring)): 表示期望返回的Response Body内容是期望的字符串。
三、额外
Java 单元测试 PowerMock
文章对 PowerMock 做了非常详尽的讲解,非常推荐。
PowerMock也是依赖 Mockito,所以我认为这两个框架用起来的差别应该不大。
原文地址:http://www.cnblogs.com/lancediarmuid/p/16850807.html
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,请务用于商业用途!
3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员!
8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载
声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性