前言
TestNG是目前很流行的Java测试框架之一,作为Java技术栈的小伙伴,TestNG也是我们做单元、接口、UI自动化的常用技术(当然Junit5很不错),所以也是入门技术之一。
那么,在实际应用中,我们常遇到的两个情况:
1、一个case有N个断言,我想执行全部断言后,最后给出testcase的执行结果,而不是在执行一个断言错误后,就终止该条testcase,判定失败。
2、在半夜执行某个testcase失败后,害怕testcase失败是因为网络等原因,期望在失败后重新再重试下。
今天介绍一下解决第一种场景的2种办法。
一、
①重新创建Assertion类,重写断言方法
/** * String对比 * @param actual * @param expected */ public static void verifyEquals(Object actual, Object expected){ try{ Assert.assertEquals(actual, expected); }catch(Error e){ errors.add(e); flag = false; } }
/** * String对比+msg * @param actual * @param expected * @param message */ public static void verifyEquals(Object actual, Object expected, String message){ try{ Assert.assertEquals(actual, expected, message); }catch(Error e){ errors.add(e); flag = false; } }
②创建新的监听类
public class AssertionListener extends TestListenerAdapter {
@Override public void onTestStart(ITestResult result) { Assertion.flag = true; Assertion.errors.clear(); }
@Override public void onTestFailure(ITestResult tr) { this.handleAssertion(tr); }
@Override public void onTestSkipped(ITestResult tr) { this.handleAssertion(tr); }
@Override public void onTestSuccess(ITestResult tr) { this.handleAssertion(tr); }
private int index = 0;
/** * 得到测试类所需的测试异常信息 * * @param tr */ private void handleAssertion(ITestResult tr) { if (!Assertion.flag) { Throwable throwable = tr.getThrowable(); if (throwable == null) { throwable = new Throwable(); } StackTraceElement[] traces = throwable.getStackTrace(); StackTraceElement[] alltrace = new StackTraceElement[0]; for (Error e : Assertion.errors) { StackTraceElement[] errorTraces = e.getStackTrace(); StackTraceElement[] et = this.getKeyStackTrace(tr, errorTraces); StackTraceElement[] message = new StackTraceElement[] { new StackTraceElement("message : " + e.getMessage() + " in method : ", tr .getMethod().getMethodName(), tr.getTestClass().getRealClass().getSimpleName(), index) }; index = 0; alltrace = this.merge(alltrace, message); alltrace = this.merge(alltrace, et); } if (traces != null) { traces = this.getKeyStackTrace(tr, traces); alltrace = this.merge(alltrace, traces); } throwable.setStackTrace(alltrace); tr.setThrowable(throwable); Assertion.flag = true; Assertion.errors.clear(); tr.setStatus(ITestResult.FAILURE); } }
/** * 根据测试类名获得该测试类的StackTraceElement数组 * * @param tr * @param stackTraceElements * @return */ private StackTraceElement[] getKeyStackTrace(ITestResult tr, StackTraceElement[] stackTraceElements) { List<StackTraceElement> ets = new ArrayList<StackTraceElement>(); for (StackTraceElement stackTraceElement : stackTraceElements) { if (stackTraceElement.getClassName().equals(tr.getTestClass().getName())) { ets.add(stackTraceElement); index = stackTraceElement.getLineNumber(); } } StackTraceElement[] et = new StackTraceElement[ets.size()]; for (int i = 0; i < et.length; i++) { et[i] = ets.get(i); } return et; }
/** * 合并两个StackTraceElement数组 * * @param traces1 * @param traces2 * @return */ private StackTraceElement[] merge(StackTraceElement[] traces1, StackTraceElement[] traces2) { StackTraceElement[] ste = new StackTraceElement[traces1.length + traces2.length]; for (int i = 0; i < traces1.length; i++) { ste[i] = traces1[i]; } for (int i = 0; i < traces2.length; i++) { ste[traces1.length + i] = traces2[i]; } return ste; }}
③加入监听注解
@Listeners(AssertionListener.class)public class MyTest { @Test public void testAssertion() { beforeClass(); try { Assertion.verifyEquals("aaa", "bbb", "aaa is wrong"); Assertion.verifyEquals("aaa", "aaa"); Assertion.verifyEquals("aaa", "ccc"); } catch (Exception e) { logger.error("testAssertion:", e); }
}}
运行结果:
FAILED: testAssertionjava.lang.Throwable at message : aaa is wrong expected [bbb] but found [aaa] in method : .testAssertion(LogonTest:41) at com.testcase.LogonTest.testAssertion(LogonTest.java:41) at message : expected [ccc] but found [aaa] in method : .testAssertion(LogonTest:43) at com.testcase.LogonTest.testAssertion(LogonTest.java:43)
小技巧:
为了省事一些可以把Listeners放到testng.xml中,例如:
<listeners> <listener class-name="com.framework.util.assertion.AssertionListener"></listener></listeners>
二、
软断言运用了SoftAssert这个类。
private SoftAssert assertion = new SoftAssert(); @Test public void testSoftAssert() { assertion.assertEquals("aaa", "bbb", "1 is wrong"); assertion.assertEquals("aaa", "aaa", "2 is wrong"); assertion.assertEquals("aaa", "ccc", "3 is wrong"); assertion.assertAll();
}
执行结果如下:
FAILED: testSoftAssertjava.lang.AssertionError: The following asserts failed:1 is wrong, 3 is wrong
注意assertEquals断言的message一定要写,否则会出现信息是null的情况,如下:
@Test public void testSoftAssert() { assertion.assertEquals("aaa", "bbb"); assertion.assertEquals("aaa", "aaa"); assertion.assertEquals("aaa", "ccc"); assertion.assertAll();
}
执行结果如下,判断不错误信息:
FAILED: testSoftAssertjava.lang.AssertionError: The following asserts failed:null, null
小技巧:
对于每次实例化SoftAssert这个类,可以写到一个basecase里面,然后采用extends继承的方式。
下次再介绍一下testng的失败重试。