TestNG针对特定的API响应结果进行重试
问题
有一个模块,提供两种方式导入数据,导入的过程是异步的。API处有校验,当有数据正在处理的时候,不能再导入,比如等待前一个导入结束。
我们针对这两种方式进行测试,当两个Test跑起来的时候,后面的case则无法通过test,因为前面的case创建了导入,导入状态还是In Process。
dependsOnMethods
所以,我们的要求就是,这两个case必须一个完成了才能进行下一个。很容易想到测试方法的依赖
@Test
public void test1() {
}
@Test(dependsOnMethods = { "test1"})
public void test2() {
}
但是刚才也说了,数据是异步处理,test1执行完只能说明请求发送并得到响应,数据不一定处理完成。
所以,此方案不行。
Retry
那就后面执行的Test如果获取到API的500响应,如果是特定Message就重试呗。
重试我会写,但有没有很优雅的方式
有,TestNG提供IRetryAnalyzer接口,可以在用例执行失败后重新执行。
看看它的默认实现
public class DisabledRetryAnalyzer implements IRetryAnalyzer {
@Override
public boolean retry(ITestResult result) {
return false;
}
}
默认就是不重试
如何使用
创建实现IRetryAnalyzer接口的类,并重写retry方法。
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
public class MyRetryAnalyzer implements IRetryAnalyzer {
private int count = 0;
private int maxCount = 3;
@Override
public boolean retry(ITestResult result) {
if (count < maxCount) {
count++;
return true;
}
return false;
}
}
在需要使用RetryAnalyzer的测试类或测试方法中,使用@Test注解并设置retryAnalyzer为MyRetryAnalyzer类即可。
import org.testng.annotations.Test;
public class MyTest {
@Test(retryAnalyzer = MyRetryAnalyzer.class)
public void testMethod() {
// 测试方法逻辑
}
}
很好,很优雅。
现在的问题是,我我不能Case不过就重试3次,我只想要特定失败的情况下---前面提到的场景,才触发重试。
那只能从retry(ITestResult result)
这个参数下手了
@Test(retryAnalyzer = MyRetryAnalyzer.class)
public void testMethod() {
var res = callAPI();
if (resp.getStatusCode() == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
Reporter.getCurrentTestResult().setAttribute("api_error_response", res.getResponseAsString());
}
}
在MyRetryAnalyzer的实现中可以通过result.getAttribute
拿到设置的值
public class MyRetryAnalyzer implements IRetryAnalyzer {
private int count = 0;
private int maxCount = 3;
@Override
public boolean retry(ITestResult result) {
if (result.getAttribute("api_error_response").toString().contains("ERROR_MESSAGE") && count < maxCount) {
count++;
return true;
}
return false;
}
}
当然再优化下,增加重试的间隔,很直接,Sleep
public class MyRetryAnalyzer implements IRetryAnalyzer {
private int count = 0;
private int maxCount = 3;
@Override
public boolean retry(ITestResult result) {
if (result.getAttribute("api_error_response").toString().contains("ERROR_MESSAGE") && count < maxCount) {
count++;
try {
Thread.sleep(3*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}