TestNG中DataProvider读取Excel时的逐行执行验证需求问题
解决TestNG数据驱动下请求与验证用例的顺序执行问题
现有TestNG测试代码,通过DataProvider读取Excel数据,优先级1的CustomerData用例执行POST请求并将响应存入静态JSONObject;多个优先级2的验证用例验证该响应。当前问题:Excel有5行数据时,会先执行完5次请求,仅最后一行的验证生效。需求是每读取一行数据,执行请求后立即执行所有验证用例,再处理下一行。
原代码如下:
public class DataProviders { @DataProvider(name="data") public String[][] getAllData() throws IOException { // 使用XLUtils(基于XSSWorkbook)读取Excel单元格数据 // 传入Excel文件名、工作表名,计算行列数 // 双层循环读取所有数据并返回 } } public class CustomerRecords { public Response response; public static JSONObject resJsonObj; @Test(priority = 1, dataProvider = "data", dataProviderClass = DataProviders.class) public void CustomerData(String cId, String fName, String lName, String email, String postCode){ // 用POJO类设置请求参数 // 调用POST接口获取响应 response = PostMehtodFromAPIClass(request); resJsonObj = new JSONObject(response.getBody().asString()); } @Test(priority=2) public void validateResponseCusID(){ // 验证逻辑,使用resJsonObj } @Test(priority=2) public void validateResponseCusName(){ // 验证逻辑,使用resJsonObj } @Test(priority=2) public void validateResponseCusPostCode(){ // 验证逻辑,使用resJsonObj } @Test(priority=2) public void validateResponseCusEmail(){ // 验证逻辑,使用resJsonObj } }
问题原因
TestNG的优先级规则是先执行所有低优先级(数值小)的方法,再执行高优先级的,因此会先跑完5次CustomerData请求,再执行验证用例。同时静态变量resJsonObj会被每次请求覆盖,最终验证用例只能拿到最后一次的响应数据。
解决方案
方案一:直接在请求方法中调用验证方法(最简单)
把验证方法改成非@Test的普通方法,在CustomerData方法执行完请求后直接调用这些验证方法。这样每执行一行数据的请求,就会立刻执行所有验证逻辑。
修改后的代码:
public class CustomerRecords { public Response response; public JSONObject resJsonObj; // 去掉static,避免跨请求覆盖 @Test(dataProvider = "data", dataProviderClass = DataProviders.class) public void CustomerData(String cId, String fName, String lName, String email, String postCode){ // 用POJO类设置请求参数 // 调用POST接口获取响应 response = PostMehtodFromAPIClass(request); resJsonObj = new JSONObject(response.getBody().asString()); // 执行所有验证逻辑 validateResponseCusID(); validateResponseCusName(); validateResponseCusPostCode(); validateResponseCusEmail(); } // 去掉@Test注解,改为普通方法 public void validateResponseCusID(){ // 验证逻辑,使用resJsonObj } public void validateResponseCusName(){ // 验证逻辑,使用resJsonObj } public void validateResponseCusPostCode(){ // 验证逻辑,使用resJsonObj } public void validateResponseCusEmail(){ // 验证逻辑,使用resJsonObj } }
方案二:使用TestNG @Factory实现实例级数据驱动
通过@Factory创建多个测试实例,每个实例对应Excel的一行数据,每个实例会先执行请求方法,再执行该实例的所有验证方法,完全隔离不同行的测试数据。
步骤1:定义存储Excel行数据的POJO
public class CustomerData { private String cId; private String fName; private String lName; private String email; private String postCode; // 构造方法 public CustomerData(String cId, String fName, String lName, String email, String postCode) { this.cId = cId; this.fName = fName; this.lName = lName; this.email = email; this.postCode = postCode; } // getter方法 public String getcId() { return cId; } public String getfName() { return fName; } public String getlName() { return lName; } public String getEmail() { return email; } public String getPostCode() { return postCode; } }
步骤2:调整DataProvider返回对象数组
public class DataProviders { @DataProvider(name="customerData") public Object[][] getAllData() throws IOException { // 原有读取Excel逻辑,得到String[][]格式数据 String[][] excelData = // 你的Excel读取代码 Object[][] data = new Object[excelData.length][1]; for(int i=0; i<excelData.length; i++){ data[i][0] = new CustomerData( excelData[i][0], excelData[i][1], excelData[i][2], excelData[i][3], excelData[i][4] ); } return data; } }
步骤3:测试类使用@Factory创建实例
public class CustomerRecords { private CustomerData customerData; private JSONObject resJsonObj; // 构造方法接收行数据 public CustomerRecords(CustomerData customerData) { this.customerData = customerData; } // @Factory生成测试实例 @Factory(dataProvider = "customerData", dataProviderClass = DataProviders.class) public static CustomerRecords createInstances(CustomerData data) { return new CustomerRecords(data); } @Test(priority = 1) public void CustomerData(){ // 从customerData中获取参数 String cId = customerData.getcId(); String fName = customerData.getfName(); // ...其他参数赋值 // 调用POST接口获取响应 Response response = PostMehtodFromAPIClass(request); resJsonObj = new JSONObject(response.getBody().asString()); } @Test(priority=2, dependsOnMethods = "CustomerData") public void validateResponseCusID(){ // 验证逻辑,使用resJsonObj } @Test(priority=2, dependsOnMethods = "CustomerData") public void validateResponseCusName(){ // 验证逻辑,使用resJsonObj } @Test(priority=2, dependsOnMethods = "CustomerData") public void validateResponseCusPostCode(){ // 验证逻辑,使用resJsonObj } @Test(priority=2, dependsOnMethods = "CustomerData") public void validateResponseCusEmail(){ // 验证逻辑,使用resJsonObj } }
方案三:使用TestNG组与依赖
把请求方法和验证方法分到同一个组,通过dependsOnGroups保证验证方法依赖请求方法,同时配置TestNG按实例执行。
测试类代码:
public class CustomerRecords { public JSONObject resJsonObj; // 去掉static @Test(priority = 1, dataProvider = "data", dataProviderClass = DataProviders.class, groups = {"customerTest"}) public void CustomerData(String cId, String fName, String lName, String email, String postCode){ // 原有请求逻辑 response = PostMehtodFromAPIClass(request); resJsonObj = new JSONObject(response.getBody().asString()); } @Test(priority=2, groups = {"customerTest"}, dependsOnGroups = {"customerTest"}) public void validateResponseCusID(){ // 验证逻辑 } // 其他验证方法同样添加groups和dependsOnGroups注解 }
对应的testng.xml配置:
<suite name="CustomerSuite" preserve-order="true" parallel="false"> <test name="CustomerTest"> <groups> <run> <include name="customerTest"/> </run> </groups> <classes> <class name="com.yourpackage.CustomerRecords"/> </classes> </test> </suite>
内容的提问来源于stack exchange,提问作者user1306926
相关产品推荐
相关产品推荐

