TestNG小技巧

前言

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的失败重试。

下一篇
举报

扫码关注云+社区

领取腾讯云代金券