Java - 测试相关

470 阅读4分钟

单元测试和集成测试

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冒烟测试

冒烟测试是集成测试的子集,检查被测系统被调用时返回正常,用于评估软件的主要功能是否正常工作。