Testng(二):监听

25 篇文章 0 订阅

1 概述

监听(Listeners),捕捉Testng的行为,并支持修改,用于定制化,如日志输出、自定义报告

监听器如下:

  • IAnnotationTransformer,只支持@Test注解转换
  • IAnnotationTransformer2,支持@Test,@DataProvider,@Factory等注解转换,比第一代更全面
  • IHookable,替代@Test测试方法,并提供回调函数,常用于权限校验
  • IInvokedMethodListener/IInvokedMethodListener2,监听before/after形为,2代增加上下文参数
  • IMethodInterceptor,拦截器,调整测试方法的执行顺序
  • IReporter,suit执行完成后生成报告
  • ISuiteListener,测试套件执行监听
  • ITestListener,测试方法执行监听

2 IAnnotationTransformer

实现IAnnotationTransformer的transform方法

参数含义:

  • 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配置

<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结尾的方法

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),以及test

配合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

5 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

6 ISuiteListener

覆写onStart 和 onFinish方法,分别对应suite开始阶段和结束阶段

7 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值