testng源码阅读之6
来源:互联网 发布:怎么开店淘宝店 编辑:程序博客网 时间:2024/05/22 01:31
两个问题
**1、tesng的架构是如何实现灵活定制listener的?通过什么方式动态加载listener
2、listener是如何抽象定义出来的**
目前常用的有reportlistenr、retryanlyzer。 testng的listener是典型的面向过程的抽象。
IConfigurationListener、IConfigurationListener2 IExecutionListener
IInvokedMethodListener、IInvokedMethodListener2 IReporter
IRetryAnalyzer ISuiteListener
以上所有的监听器,都要继承一个接口ITestNGListener
/** * This is a marker interface for all objects that can be passed * as a -listener argument. * * @author cbeust */public interface ITestNGListener {}
这个接口的主要作用。就是可以所有的接口,都可以通过instanceof来查询,得到他的类型,方便执行引擎进行辨别跟加载
接着上边说的。所有的listener都是面向过程定义的。执行引擎最终执行的部分 1、整个测试集的参数加载,配置加载 2、测试集执行前、执行后
3、测试方法执行前、执行后 4、失败是否可以重试 5、测试报告的生成有关细节。listener如何加载到线程的上下文,如何在适当的时候使用这些listener。
核心就在TestNG这个类里边。最初的入口。在这里,会提前加载好所有的listener。
所有的listener都是定义成一个Set或者List。方便后边执行的时候使用。
public void addListener(Object listener) { if (! (listener instanceof ITestNGListener)) { exitWithError("Listener " + listener + " must be one of ITestListener, ISuiteListener, IReporter, " + " IAnnotationTransformer, IMethodInterceptor or IInvokedMethodListener"); } else { if (listener instanceof ISuiteListener) { addListener((ISuiteListener) listener); } if (listener instanceof ITestListener) { addListener((ITestListener) listener); } if (listener instanceof IReporter) { addListener((IReporter) listener); } if (listener instanceof IAnnotationTransformer) { setAnnotationTransformer((IAnnotationTransformer) listener); } if (listener instanceof IMethodInterceptor) { setMethodInterceptor((IMethodInterceptor) listener); } if (listener instanceof IInvokedMethodListener) { addInvokedMethodListener((IInvokedMethodListener) listener); } if (listener instanceof IHookable) { setHookable((IHookable) listener); } if (listener instanceof IConfigurable) { setConfigurable((IConfigurable) listener); } if (listener instanceof IExecutionListener) { addExecutionListener((IExecutionListener) listener); } if (listener instanceof IConfigurationListener) { getConfiguration().addConfigurationListener((IConfigurationListener) listener); } } }
一层层的往上configure调这里,然后是privatemain然后main入口。
下边看看具体在某个环节,他们是怎么执行的。
几乎所有的listener都是只定义了两个操作 onStart()、onFinish()
每一个层级的执行,都是用的xxxrunner的方式。比如suiteRunner、methodRunner.这些类保存了所有上下文,
而对应的suiteRunnerWorker、TestMethodWorker 就是真正的执行器。包括执行排序,执行结果,执行过程 的日志等等
他们都实现了一个共同的接口。任务超时跟优先级。同时这个是泛型的接口相对来说,抽象程度已经很高了。
如果只是实现单线程,其实没有必要继承runnable跟comparable。但是因为要支持多线程,所以要实现这个。
public class TestMethodWorker implements IWorker<ITestNGMethod>/** * A runnable object that is used by {@code GraphThreadPoolExecutor} to execute * tasks */public interface IWorker<T> extends Runnable, Comparable<IWorker<T>> { /** * @return list of tasks this worker is working on. */ List<T> getTasks(); /** * @return the maximum time allowed for the worker to complete the task. */ long getTimeOut(); /** * @return the priority of this task. */ int getPriority();}
我们看看其中一个
SuiteRunnerWorker,是如何执行的。
关键的函数,runnalbe的override。在这里执行所有的listner的onStart(),结束后运行onFinish()
由于在testNG入口类就已经校验过所有的listener的类型,跟个数,比如,只允许有一个自定义的reportlistener。所以这些listner的执行的顺序
理论上是随机的。
@Override public void run() { invokeListeners(true /* start */); try { privateRun(); } finally { invokeListeners(false /* stop */); } }private void invokeListeners(boolean start) { for (ISuiteListener sl : m_listeners) { if (start) { sl.onStart(this); } else { sl.onFinish(this); } } }
好,到这里,整个框架的流程我们基本弄清楚了。一些关键的点已经厘清。
回归最开始的地方。这些listener是怎么被加载进来的呢?configure 的时候会加载。有两种方式,一种是命令行configure。
那么另外一种呢?另外一种就是直接解析xml的。这部分一般是由插件完成。实际调用的仍然是这里
public static TestNG privateMain(String[] argv, ITestListener listener) { TestNG result = new TestNG(); if (null != listener) { result.addListener(listener); } // // Parse the arguments // try { CommandLineArgs cla = new CommandLineArgs(); m_jCommander = new JCommander(cla, argv); validateCommandLineParameters(cla); result.configure(cla); } catch(ParameterException ex) { exitWithError(ex.getMessage()); } // // Run // try { result.run(); } catch(TestNGException ex) { if (TestRunner.getVerbose() > 1) { ex.printStackTrace(System.out); } else { error(ex.getMessage()); } result.setStatus(HAS_FAILURE); } return result; }
- testng源码阅读之6
- testng源码阅读之二
- testng源码阅读之三
- testng源码阅读之四
- testng源码阅读之5
- testng源码阅读之读后感
- testng源码阅读之入口在哪
- testng源码阅读之多线程包
- 源码阅读之ArrayList
- 源码阅读之Vector
- Spring 源码阅读之BeanFactory
- Azkaban源码阅读之AzkabanApplication
- Azkaban源码阅读之CachingFlowManager
- 源码阅读之函数指针
- JDK源码阅读之ArrayList
- JDK源码阅读之LinkedList
- JDK源码阅读之Arrays
- JDK源码阅读之String
- QT中定时器使用办法
- Android AppBarLayout以及ToolBar去除阴影
- TinkerPop中的遍历:图的遍历步骤(1/3)
- 在ROS中添加多个机器人模型
- 高性能 javaScript 之遍历对象属性
- testng源码阅读之6
- 工厂模式
- JS DOM(一)
- Linux自带JDK安装目录查询
- Java作业@笔试题@2017.11.04-11.05
- 资源视频学习JavaSE阶段整理笔记
- Cake ZOJ
- 【OpenCV】图像金字塔
- cmd 命令提示符