使用testng listener实现测试用例失败重跑功能

本文介绍了如何利用TestNG的Listener功能实现测试用例失败后的重跑。通过创建TestngRetry和RetryListener两个文件,并设置retryAnalyzer属性或在testng.xml中配置listener,可以实现失败用例的重试。同时,为了排除重复用例影响测试结果,通过重写TestListenerAdapter的onFinish方法过滤掉已重跑的用例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们通过重写testng的retry方法和transform方法来实现用例失败重跑的功能。

首先添加两个文件

TestngRetry.java

public class TestngRetry implements IRetryAnalyzer {
	private static Logger logger = Logger.getLogger(TestngRetry.class);
	private static int maxRetryCount = 3;
	private int retryCount = 1;

	@Override
	public boolean retry(ITestResult result) {
		if (retryCount <= maxRetryCount) {
			String message = "Running retry for '" + result.getName()
					+ "' on class " + this.getClass().getName() + " Retrying "
					+ retryCount + " times";
			logger.info(message);
			Reporter.setCurrentTestResult(result);
			Reporter.log("RunCount=" + (retryCount + 1));
			retryCount++;
			return true;
		}
		return false;
	}
}

RetryListener.java

public class RetryListener implements IAnnotationTransformer {
	@Override
	public void transform(ITestAnnotation annotation, Class testClass,
			Constructor testConstructor, Method testMethod) {
		IRetryAnalyzer retry = annotation.getRetryAnalyzer();
		if (retry == null) {
			annotation.setRetryAnalyzer(TestngRetry.class);
		}
	}
}

添加以上两个文件之后,有两种方法可以使用我们的listener进行监听:

  • 在Test标签中添加retryAnalyzer属性
@Test(retryAnalyzer = com.xxx.retry.RetryListener.class)
  • 在testng.xml文件中配置listener
<test name="test1">
	<listeners>
		<listener class-name="com.xxx.retry.RetryListener" />
	</listeners>
	<classes>
		<class name="com.xxx.test.NewTest" />
	</classes>
</test>

做完上面的工作,我们就可以实现失败重跑的功能了。但是,每次用例重跑之后,每次失败的结果也记录在运行结果中了,测试结果中运行的用例数增加了,不利于我们查看测试结果。因此,我们还需要把重复的用例去掉。
这个我们通过重写TestListenerAdapter中的onFinish方法实现:

TestngListener.java

public class TestngListener extends TestListenerAdapter {
	private static Logger logger = Logger.getLogger(TestngListener.class);
	@Override
	public void onFinish(ITestContext testContext) {
		super.onFinish(testContext);

		// List of test results which we will delete later
		ArrayList<ITestResult> testsToBeRemoved = new ArrayList<ITestResult>();
		// collect all id's from passed test
		Set<Integer> passedTestIds = new HashSet<Integer>();
		for (ITestResult passedTest : testContext.getPassedTests()
				.getAllResults()) {
			logger.info("PassedTests = " + passedTest.getName());
			passedTestIds.add(getId(passedTest));
		}

		Set<Integer> failedTestIds = new HashSet<Integer>();
		for (ITestResult failedTest : testContext.getFailedTests()
				.getAllResults()) {
			logger.info("failedTest = " + failedTest.getName());
			int failedTestId = getId(failedTest);

			// if we saw this test as a failed test before we mark as to be
			// deleted
			// or delete this failed test if there is at least one passed
			// version
			if (failedTestIds.contains(failedTestId)
					|| passedTestIds.contains(failedTestId)) {
				testsToBeRemoved.add(failedTest);
			} else {
				failedTestIds.add(failedTestId);
			}
		}

		// finally delete all tests that are marked
		for (Iterator<ITestResult> iterator = testContext.getFailedTests()
				.getAllResults().iterator(); iterator.hasNext();) {
			ITestResult testResult = iterator.next();
			if (testsToBeRemoved.contains(testResult)) {
				logger.info("Remove repeat Fail Test: " + testResult.getName());
				iterator.remove();
			}
		}

	}

	private int getId(ITestResult result) {
		int id = result.getTestClass().getName().hashCode();
		id = id + result.getMethod().getMethodName().hashCode();
		id = id
				+ (result.getParameters() != null ? Arrays.hashCode(result
						.getParameters()) : 0);
		return id;
	}
}

把listener添加到testng.xml中,当前testng.xml为:

<test name="test1">
	<listeners>
		<listener class-name="com.xxx.retry.RetryListener" />
		<listener class-name="com.xxx.retry.TestngListener" />
	</listeners>
	<classes>
		<class name="com.xxx.test.NewTest" />
	</classes>
</test>

OK,结束。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值