Testng(二):監聽

1 前言

監聽(Listeners),捕捉Testng的行爲,並支持修改,用於定製化,如日誌輸出、自定義報告html

監聽器以下:java

  • IAnnotationTransformer,只支持@Test註解轉換
  • IAnnotationTransformer2,支持@Test,@DataProvider,@Factory等註解轉換,比第一代更全面
  • IHookable,替代@Test測試方法,並提供回調函數,經常使用於權限校驗
  • IInvokedMethodListener/IInvokedMethodListener2,監聽before/after形爲,2代增長上下文參數
  • IMethodInterceptor,攔截器,調整測試方法的執行順序
  • IReporter,suit執行完成後生成報告
  • ISuiteListener,測試套件執行監聽
  • ITestListener,測試方法執行監聽

2 IAnnotationTransformer

實現IAnnotationTransformer的transform方法ide

參數含義:函數

  • ITestAnnotation,即@Test註解自己,能夠修改它的各類屬性,如dataProvider,enabled,invocationCount等
  • Class,當@Test應用於class時,指向當前類;不然值爲null
  • Constructor,同上,做用對象爲構造器
  • Method,同上,做用對象爲方法

需求:以2結尾的方法執行2次測試

public class MyTransformer implements IAnnotationTransformer {
    @Override
    public void transform(ITestAnnotation iTestAnnotation, Class aClass, Constructor constructor, Method method) {
        if (method.getName().endsWith("2")) {
            iTestAnnotation.setInvocationCount(2);
        }
    }
}
public class App {

    @Test
    public void test_1() {
        System.out.println("Just run once");
    }

    @Test
    public void test_2() {
        System.out.println("Run twice");
    }
}
---------------------------
Just run once
Run twice
Run twice

testng.xml配置ui

<suite name="Suite1" verbose="1" >
    <listeners>
        <listener class-name="MyTransformer"/>
    </listeners>

    <test name="Test1">
        <classes>
            <class name="App" />
        </classes>
    </test>
</suite>
@Listeners不支持IAnnotationTransformer 和 IAnnotationTransformer2,因此只能在testng.xml上配置監聽器,固然命令行也可行

3 IHookable

實現IHookable的run方法命令行

調用IHookCallBack的runTestMethod方法,能夠回調原測試方法日誌

需求:只執行以2結尾的方法code

public class MyHookable implements IHookable {

    @Override
    public void run(IHookCallBack callBack, ITestResult testResult) {
        if (testResult.getMethod().getMethodName().endsWith("2")) {
            callBack.runTestMethod(testResult);
        }
    }
}
@Listeners({MyHookable.class})
public class App {

    @Test
    public void test_1() {
        System.out.println("Just run once");
    }

    @Test
    public void test_2() {
        System.out.println("Run twice");
    }
}
-----------------------------
Run twice

4 IInvokedMethodListener

適用於configuration(suit, test, class),以及testorm

配合log4j,能夠記錄詳細的執行過程

public class MyInvokedMethodListener implements IInvokedMethodListener {
    @Override
    public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
        System.out.println("begin to run " + testResult.getName());
    }

    @Override
    public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
        System.out.println("end to run " + testResult.getName() + ", result code is " + testResult.getStatus());
    }
}
@Listeners({MyInvokedMethodListener.class})
public class App {

    @BeforeClass
    public void setup() {
        System.out.println("initial env");
    }

    @Test
    public void test_1() {
        System.out.println("test 1");
        Assert.assertTrue(true);
    }

    @Test
    public void test_2() {
        System.out.println("test 2");
        Assert.assertTrue(false);
    }
}
---------------------
begin to run setup
initial env
end to run setup, result code is 1
begin to run test_1
test 1
end to run test_1, result code is 1
begin to run test_2
test 2
end to run test_2, result code is 2

4 IMethodInterceptor

需求:優先執行fast組成員方法

public class MyMethodInterceptor implements IMethodInterceptor {
    @Override
    public List<IMethodInstance> intercept(List<IMethodInstance> methods, ITestContext context) {
        List<IMethodInstance> result = new ArrayList<>();

        methods.forEach(method -> {
            Test test = method.getMethod().getConstructorOrMethod().getMethod().getAnnotation(Test.class);
            Set<String> groups = new HashSet<>();
            Arrays.stream(test.groups()).forEach(group -> groups.add(group));

            if (groups.contains("fast")) {
                result.add(0, method);
            } else {
                result.add(method);
            }
        });
        return result;
    }
}
public class App {

    @Test
    public void test_1() {
        System.out.println("first to run");
    }

    @Test(groups = {"fast"})
    public void test_2() {
        System.out.println("second to run");
    }

    @Test void test_3() {
        System.out.println("third to run");
    }
}
---------------------------------
second to run
first to run
third to run

5 ISuiteListener

覆寫onStart 和 onFinish方法,分別對應suite開始階段和結束階段

6 ITestListener

對應測試方法的7種狀態:

  • onStart,測試類實例化後執行
  • onFinish,測試類下的全部測試方法完成後執行
  • onTestStart,每次執行測試方法前執行
  • onTestSuccess,每次測試方法執行成功後執行
  • onTestFailure,每次測試方法執行失敗後執行
  • onTestSkipped,每次測試方法跳過期執行
  • onTestFailedButWithinSuccessPercentage,每次測試方法執行失敗,但正確率符合successPercentage要求

實現ITestListener接口,須要覆寫上述7種方法,比較麻煩

所以實際偏向於繼承TestListenerAdapter

7 IReporter

獲取testng執行結果,與html模板結合能夠定製測試報告

public class MyReporter implements IReporter {
    @Override
    public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
        suites.forEach(suite -> {
            System.out.println("測試方法以下:");
            suite.getAllMethods().forEach(iTestNGMethod -> System.out.println("\t" + iTestNGMethod.getMethodName()));

            System.out.println("報告輸出路徑:" + suite.getOutputDirectory());

            suite.getResults().values().forEach(iSuiteResult -> {
                ITestContext iTestContext = iSuiteResult.getTestContext();

                Set<ITestResult> passedTests = iTestContext.getPassedTests().getAllResults();
                System.out.println("執行成功的方法:" + passedTests.size());
                passedTests.forEach(iTestResult -> {
                    System.out.println("\t" + iTestResult.getName());
                    System.out.println("\t\t開始時間:" + iTestResult.getStartMillis());
                    System.out.println("\t\t結束時間:" + iTestResult.getEndMillis());
                });

                Set<ITestResult> failedTests = iTestContext.getFailedTests().getAllResults();
                System.out.println("執行失敗的方法:" + failedTests.size());
                failedTests.forEach(iTestResult -> {
                    System.out.println("\t" + iTestResult.getName());
                    System.out.println("\t\t開始時間:" + iTestResult.getStartMillis());
                    System.out.println("\t\t結束時間:" + iTestResult.getEndMillis());
                });
            });
        });
    }
}
@Listeners({MyReporter.class})
public class App {

    @Test
    public void test_1() {
        System.out.println("first to run");
    }

    @Test
    public void test_2() {
        System.out.println("second to run");
    }

    @Test
    public void test_3() {
        Assert.assertTrue(false);
    }
}
------------------------
測試方法以下:
    test_1
    test_2
    test_3
報告輸出路徑:E:\code\java\lab\test-output\Default Suite
執行成功的方法:2
    test_2
        開始時間:1541921094204
        結束時間:1541921094204
    test_1
        開始時間:1541921094188
        結束時間:1541921094188
執行失敗的方法:1
    test_3
        開始時間:1541921094204
        結束時間:1541921094204
相關文章
相關標籤/搜索