TestNG单元测试实战
对软件中最小可测试单元进行验证。小到一个方法,大到一个类、一个模块。都可以用单元测试覆盖。
现状:
面对日复一日排满的需求,没有时间去写。
再者业务逻辑变化快,对应的单元测试代码也得调整。不愿写。
用postman,接口api也能满足http测试。
写单测好处:
在线测试分支覆盖不全的情况。
判断方法的返回值和预期值是否一致。
阅读单元测试代码能简单快速的了解逻辑。方便后面的同事了解此方法功能。以及怎么使用。
如果不写单测,那我们可能会用postman或swagger-ui来测试某个controller接口。
但很多时候我们需要对service中多个分支,对某个工具类验证代码正确性,这时候还不涉及接口的调用,以及接口不能覆盖全异常分支的情况。此时这种场景就可以用单测来完成。
Junit和TestNG都是Java测试框架。
看Testng官网介绍: TestNG - Welcome
对比Junit,TestNG优势如下:
注解更全
支持依赖测试
支持测试组
支持多线程测试
引入maven配置
org.testng
testng
6.9.10
test
org.springframework.boot
spring-boot-starter-test
2.2.2.RELEASE
test
简单示例:
@SpringBootTest
public class DemoTest extends AbstractTestNGSpringContextTests {
@Autowired
private IDemoService service;
@Autowired
private DemoController demoController;
@Autowired
private PreprocessConfig preprocessConfig;
@Autowired
private AuthInterceptor interceptor;
public MockMvc mockMvc;
//测试方法前运行
@BeforeMethod
public void setup(){
//通过注册一个或多个controller实例和配置springmvc编程方式来构建一个mockmvc实例。
mockMvc = MockMvcBuilders.standaloneSetup(demoController).
//添加拦截器
addInterceptors(interceptor).
//请求数据预处理
setControllerAdvice(preprocessConfig).
build();
}
@Test
public void testDemoList() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/demo/list")
.header("token", "xxxxxx")
.contentType(MediaType.TEXT_HTML_VALUE)
.queryParam("ascs", "createDate"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string(Matchers.notNullValue()));
}
@Test
public void testProcessMerge() {
int num = service.processMerge(1);
Assert.assertEquals(num, 1);
}
}
此单元测试类中包含了service和controller测试。其中setup()用于构建MockMvc实例。
MockMvc: 服务器端Spring MVC测试支持的主要入口点。可调用其perform方法来构建请求。
SpringBootTest注解: 此注解表明基于spring boot启动的测试类。
AbstractTestNGSpringContextTests抽象类: 集成了spring测试上下文框架。 此抽象类也实现了ApplicationContextAware接口,spring容器初始化时,会注入spring应用上下文。
如前端传的string需转成实体属性中LocalDateTime格式,则需要对请求参数预处理,可定义一个日期预处理类:
@ControllerAdvice
public class PreprocessConfig{
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.isNotBlank(text)){
this.setValue(LocalDateTime.parse(text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
} else {
this.setValue(null);
}
}
});
}
}
ControllerAdvice和InitBinder注解实现全局数据预处理。
AbstractTransactionalTestNGSpringContextTests抽象类继承自AbstractTestNGSpringContextTests抽象类,用于加载spring配置,支持事务。
在测试方法上加入@Rollback用于事物回滚处理。
@BeforeSuite:在该套件中所有测试用例执行前运行。
@AfterSuite:在该套件中所有测试用例执行后运行。
@BeforeGroups:调用属于该组的第一个方法前运行。
@AfterGroups:调用属于该组最后一个方法后运行。
@BeforeClass:在调用当前类第一次测试方法前运行。
@AfterClass:当前类所有测试方法结束后运行。
@BeforeMethod:在每个测试方法开始运行前执行。
@AfterMethod:在每个测试方法运行结束后执行。
@Test:表明为测试方法。
执行顺序:@BeforeSuite -> @BeforeClass -> @BeforeGroups -> @BeforeMethod -> @Test -> @AfterMethod -> @AfterGroups -> @AfterClass -> @AfterSuite。
其中Test注解中有如下方法:
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({METHOD, TYPE, CONSTRUCTOR})
public @interface Test {
public String[] groups() default {};
public String[] dependsOnGroups() default {};
public String[] dependsOnMethods() default {};
public int threadPoolSize() default 0;
public String dataProvider() default "";
}
可以用dependsOnGroups表明依赖的组,dependsOnMethods设置方法依赖,threadPoolSize配置线程数等等。