TestNG针对特定的API响应结果进行重试

发布时间 2023-03-29 23:58:31作者: luzemin

问题

有一个模块,提供两种方式导入数据,导入的过程是异步的。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;
    }

}

结果