您好,我是码农飞哥,感谢您阅读本文!如果此文对您有所帮助,请毫不犹豫的一键三连吧。小伙伴们,有啥想看的,想问的,欢迎积极留言。上一篇文章对TestNG做了一个简单的体验。我们了解了其是什么,有什么用,重点介绍了其各种注解。但是这些都不够深入,不够爽。实际项目中怎么运用呢?没有说,实在不过瘾。
这篇文章就让我们来深入体验一下TestNG。看看到底好不好用,用的爽不爽。
首先,还是搭建一个SpringBoot框架的项目,怎么搭建项目,在此就不赘述了,想了解的朋友可以参考这篇文章Spring Boot 学习01-----搭建一个简单的spring-boot-demo
项目搭建好之后,这里添加了几个待测试的方法。代码如下:
@RestController
public class TestNgController {
@Autowired
private TestNgService testNgService;
@PostMapping("/v1/user/add")
public String addUser(String userName, String password) {
boolean result = testNgService.saveUser(userName, password);
return result ? "{\"code\":\"200\",\"msg\":\"用户保存成功\"}"
: "{\"code\":\"500\",\"msg\":\"用户保存失败\"}";
}
@GetMapping("/v1/user/get")
public String getUser(String userName) {
boolean result = testNgService.getUserByName(userName);
return "{\"code\":\"200\",\"msg\":\"获取用户成功\"}";
}
@RequestMapping("/v1/user/update")
public String updateUser(@RequestBody User user) {
boolean result = testNgService.updateUser(user);
return result ? "{\"code\":\"200\",\"msg\":\"用户修改成功\"}"
: "{\"code\":\"500\",\"msg\":\"用户修改失败\"}";
}
}
这里分别有:
/v1/user/add
,请求类型是application/form-data
。/v1/user/get
,请求类型是application/form-data
。/v1/user/update
,这个的请求类型是application/json
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.testnggroupId>
<artifactId>testngartifactId>
<version>6.10version>
<scope>testscope>
dependency>
@SpringBootTest
public class TestNgControllerTest extends AbstractTestNGSpringContextTests {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@BeforeClass
public void setUp(){
//必须用webAppContextSetup方法设置web环境
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
//通用返回结果的封装
public String getResultCode(MockHttpServletRequestBuilder requestBuilder) {
try {
MvcResult mvcResult = mockMvc.perform(requestBuilder)
.andDo(print())
.andExpect(status().isOk())
.andReturn();
String result = mvcResult.getResponse().getContentAsString();
JSONObject jsonObject = JSON.parseObject(result);
return jsonObject.getString("code");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
是不是感觉跟前面Junit 整合SpringBoot的单元测试基类有点像呢?对的没错,长的确实有点像,因为其中MvcResult对象和MockMvc对象因为来自spring-test。所以,getResultCode方法是一模一样的,都是针对返回类型是application/json
格式的返回做了处理。
需要特别注意的是与Junit的不同点:
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextBeforeTestClass")
protected void springTestContextPrepareTestInstance() throws Exception {
this.testContextManager.prepareTestInstance(this);
}
所以在@BeforeClass
运行之前执行的方法都不能获取对象。即使用@BeforeSuite
或者是@BeforeTest
注解修饰的话,则初始化方法运行时ApplicationContext还没有被注入进来。如果用@BeforeMethod
修饰的话,则每个测试方法执行之前都会执行一次。
补充说明:@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextBeforeTestClass")
dependsOnMethods属性表示该方法依赖于springTestContextBeforeTestClass方法,就是说springTestContextBeforeTestClass必须要先于springTestContextPrepareTestInstance执行,同时alwaysRun = true
表示依赖者和被依赖者之间必须不存在成功失败的因果关系,只需要被依赖的方法执行即可。
基类编写好之后,就相当于是打好了基础,下面只要搬砖了。首先编写保存用户的测试方法
@Test
public void testAddUser() {
System.out.println("线程="+Thread.currentThread().getName()+"执行testAddUser");
//保存成功
{
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/v1/user/add")
.param("userName", "张三")
.param("password", "123");
String resultCode = getResultCode(requestBuilder);
Assert.assertEquals("200", resultCode);
}
//保存失败的情况
{
MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/v1/user/add")
.param("userName", "李四")
.param("password", "123");
String resultCode = getResultCode(requestBuilder);
Assert.assertEquals("500", resultCode);
}
}
这里有保存成功和保存失败两种情况。代码的编写跟使用Junit时是一模一样的,还是实例化MockHttpServletRequestBuilder对象,传入接口地址和入参。在此不在赘述了。执行结果是:
直接运行单元测试类,三个测试方法的运行线程都是主线程,不是说testNG可以进行并发测试么?没看到呀,不要着急,这就来进行并发测试。
建立一个TestNG的XML文件,命名为TestNgControllerTestSuite.xml。
<suite name="Suite" parallel="methods" thread-count="4">
<test name="Test">
<classes>
<class name="com.jay.testng.TestNgControllerTest"/>
classes>
test>
suite>
其中与并发测试相关的配置是:
<suite name="Suite" parallel="methods" thread-count="4">
在当前测试规划的执行过程中,为每个方法(不管是不是通过@Test修饰的方法)进行并发执行,最多4个线程,下面就是运行结果
当然还有其他的配置,比如:
<suite name="Suite" parallel="tests" thread-count="4">
在当前测试规划的执行过程中,为每个测试方法(只有通过@Test修饰的方法)进行并发执行,最多4个线程。
2. 针对测试类
<suite name="Suite" parallel="classes" thread-count="4">
在当前测试规划的执行过程中,为每个测试类的执行使用单独的线程(该测试类中的测试方法共享一个线程),最多并发4个线程。
本文详细介绍了TestNG与SpringBoot的整合,还介绍了并发测试。