单元测试和集成测试
0.概述
软件测试(Software Testing)是使用人工或自动的手段来运行或测定某个软件系统的过程,其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。软件测试是软件研发过程中软件质量保证重要的一环。
软件测试按照测试阶段来划分:
- 单元测试
- 集成测试
- 系统测试
- 验收测试(用户测试)
按照测试手段来区分:
- 黑盒测试
- 白盒测试
- 动态测试
- 静态测试
- …
按照类型来划分:
- 功能测试
- 性能测试
- 安全测试
- 兼容性测试
- …
其它测试概念:
- 冒烟测试
- 回归测试
- Monkey测试
- A/B测试
- 线上测试
本文主要关注单元测试和集成测试。
1.单元测试(Unit Testing, UT)
1.1概念
单元测试用于测试软件的基本组成单元,确保其正确性。在面向对象编程中,单元通常是单个方法。
单元测试应该全部在内存中执行,即意味着测试代码和被测试代码不应该:
- 调用进入其它方法
- 访问网络
- 访问数据库
- 使用文件系统
- 启动线程
被测代码应和其所依赖的代码进行隔离,可以Mock所有依赖代码。
单元测试通过可以证明各单元独立工作时是正常的,但无法证明结合在一起也能够正常工作。
1.2测试web层
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class) // 启动Spring MVC容器,能提供MockMvc类型的bean用来模拟发送请求
public class UserControllerTest {
@Autowired
private MockMvc mvc;
@MockBean // 表示userService是模拟的bean
private UserService userService;
@Test
public void testGetUser() throws Exception {
UserVo param = new UserVo(1, null, null);
UserVo vo = new UserVo(null, "zhangsan", "男");
Mockito.when(userService.getUser(1)).thenReturn(vo); // 打桩:为模拟的bean自定义预期行为
MvcResult mvcResult = mvc.perform(
MockMvcRequestBuilders.post("/getuser")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(JsonUtils.bean2Json(param))
) // 发起POST请求
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print()) // 打印执行结果;
.andReturn();
ApiResult result = JsonUtil.json2bean(result.getResponse().getContentAsString(), ApiResult.class);
Assertions.assertThat(result.getErrorCode(), is(0)); // 断言结果
}
}
复制代码
1.3测试dao层
持久层的测试方案跟具体的持久层技术相关。
1.4测试service层
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserDao userDao;
@Test
public void getUser() {
int id = 1;
User user = new User(1, "zhangsan", id);
Mockito.when(userDao.getUserById(id)).thenReturn(user);
Assertions.assertThat(userDao.getUserById(id), is(user));
}
}
复制代码
1.5 Junit基本注解介绍
@RunWith
在Junit中有很多Runner,他们负责调用你的测试代码,每个Runner都有各自特殊的功能,根据需要选择不同的Runner来运行测试代码。
SpringJUnit4ClassRunner用于集成测试需要加载spring上下文时使用。
MockitoJUnitRunner用于单元测试。
@BeforeClass
在所有测试方法执行前执行一次,一般写整体初始化代码
@AfterClass
在所有测试方法执行后执行一次,一般写销毁和释放资源的代码
@Before
在每个测试方法执行前执行,用来重置数据
@After
在每个方法执行后执行
在默认情况下,maven-surefire-plugin的test目标会执行测试源码路径(默认为src/test/java/)下所有符合命名模式的测试类:
- 以Test开头的类
- 以Test结尾的类
- 以TestCase结尾的类
单元测试主要是在Dao层和Service层进行,所有依赖的类都应该进行mock。
2.集成测试(Integration and Testing,I&T)
2.1概念
集成测试是在所有组件都已经开发完成之后,进行组装测试。单元测试不同之处是,集成测试可以使用线程、访问数据库或者做保证所有的代码和不同的环境下都会正确工作。
集成测试有两种测试方式:启动服务进行测试、使用模拟环境测试。
2.2启动服务进行测试
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void getUser() throws Excetpion {
UserVo param = new UserVo(1, null, null);
ApiResult result = restTemplate.postForObject("/getUser", param, ApiResult.class);
Assertions.assertThat(result.getErrorCode(), is(0));
}
public ApiResult login() {}
public void logout() {}
// 登录-登出 测试
@Test
public void testUser() throws Excetpion {
login();
getUser();
logout();
}
}
复制代码
2.3使用模拟环境进行测试
@RunWith(SpringRunner.class)
@WebMvcTest
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void getUser() throw Exception {
mvc.perform(
MockMvcRequestBuilders.post("/getUser")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(JsonUtils.bean2Json(param))
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print()) // 打印执行结果;
.andReturn();
ApiResult result = JsonUtil.json2bean(result.getResponse().getContentAsString(), ApiResult.class);
Assertions.assertThat(result.getErrorCode(), is(0)); // 断言结果
}
}
复制代码
3.测试框架
Spring Boot中的spring-boot-starter-test集成了多个类型的测试框架,用来便于我们进行单元测试和集成测试:
- Junit4: Java应用单元测试事实上的标准。
- Spring Test & Spring Boot Test: Spring Boot应用的工具和集成测试支持。
- AssertJ: 一个流式断言库,支持一条断言语句对实际值同时断言多个校验点。
- Hamcrest: 一个匹配器(也成为约束或谓词)库。
- Mockito: 一个Java mocking框架。
- JSONassert: 一个JSON断言库,用来比较JSON数据。
- JsonPath: XPath在JSNO的应用,用来解析JSON数据。
4.其它
4.1系统测试
典型的黑盒测试,同应用程序的功能需求密切相关。这类测试应由测试人员完成。
4.2冒烟测试
冒烟测试是集成测试的子集,检查被测系统被调用时返回正常,用于评估软件的主要功能是否正常工作。