testng源码阅读之三
来源:互联网 发布:2016电脑安全软件排行 编辑:程序博客网 时间:2024/05/17 02:43
接着上文继续分析testRunner的privateRun的流程。
上一篇讲清楚了,测试方法执行前的一些准备工作。包括执行的方法,顺序等等。
接下来要分析两个事情:
1、testrunner的上下文从何而来,如何定义的
2、测试结果是如何收集的,就是testresult的多线程处理
/** * Run all the ITestNGMethods passed in through the constructor. * * @see java.lang.Runnable#run() */ @Override public void run() { for (IMethodInstance testMthdInst : m_methodInstances) { ITestNGMethod testMethod = testMthdInst.getMethod(); ITestClass testClass = testMethod.getTestClass(); invokeBeforeClassMethods(testClass, testMthdInst); // Invoke test method try { invokeTestMethods(testMethod, testMthdInst.getInstances(), m_testContext); } finally { invokeAfterClassMethods(testClass, testMthdInst); } } }
多线程的run方法的定义。上下文是m_testContext。这变量在TestMethodWorker里边是final
private final ITestContext m_testContext; public TestMethodWorker(IInvoker invoker, IMethodInstance[] testMethods, XmlSuite suite, Map<String, String> parameters, ITestNGMethod[] allTestMethods, ConfigurationGroupMethods groupMethods, ClassMethodMap classMethodMap, ITestContext testContext) {
层层调用。一步步的回朔回去。
testRunner的调用。上下文传的是testrunner本身。
public class TestRunner implements ITestContext, ITestResultNotifier, IThreadWorkerFactory<ITestNGMethod>@retinder-->这里是因为TestRunner本身就实现了ITestContext;private TestMethodWorker createTestMethodWorker( List<IMethodInstance> methodInstances, Map<String, String> params, Class<?> c) { return new TestMethodWorker(m_invoker, findClasses(methodInstances, c), m_xmlTest.getSuite(), params, m_allTestMethods, m_groupMethods, m_classMethodMap, this); }
既然上下文是TestRunner本身,我们看看这个类Getter跟Setter。
上下文主要包括配置(configuration)、监听器(listener)、before、after这些。所有的东西,都在构造函数里边初始化。
public TestRunner(IConfiguration configuration, ISuite suite, XmlTest test, boolean skipFailedInvocationCounts, List<IInvokedMethodListener> listeners) { init(configuration, suite, test, suite.getOutputDirectory(), suite.getAnnotationFinder(), skipFailedInvocationCounts, listeners); } private void init(IConfiguration configuration, ISuite suite, XmlTest test, String outputDirectory, IAnnotationFinder annotationFinder, boolean skipFailedInvocationCounts, List<IInvokedMethodListener> invokedMethodListeners) { m_configuration = configuration; m_xmlTest= test; m_suite = suite; m_testName = test.getName(); m_host = suite.getHost(); m_testClassesFromXml= test.getXmlClasses(); m_skipFailedInvocationCounts = skipFailedInvocationCounts; setVerbose(test.getVerbose()); boolean preserveOrder = "true".equalsIgnoreCase(test.getPreserveOrder()); m_methodInterceptor = preserveOrder ? new PreserveOrderMethodInterceptor() : new InstanceOrderingMethodInterceptor(); m_packageNamesFromXml= test.getXmlPackages(); if(null != m_packageNamesFromXml) { for(XmlPackage xp: m_packageNamesFromXml) { m_testClassesFromXml.addAll(xp.getXmlClasses()); } } m_annotationFinder= annotationFinder; m_invokedMethodListeners = invokedMethodListeners; m_invoker = new Invoker(m_configuration, this, this, m_suite.getSuiteState(), m_skipFailedInvocationCounts, invokedMethodListeners); if (suite.getParallel() != null) { log(3, "Running the tests in '" + test.getName() + "' with parallel mode:" + suite.getParallel()); } setOutputDirectory(outputDirectory); // Finish our initialization init(); }
然后我们来看看他被哪些方法调用,是如何跟最初的入口链接起来的。
这里的就是SuiteRunner会调用的地方。这里的方法是属于其中的静态内部类。
private static class DefaultTestRunnerFactory implements ITestRunnerFactory {
一步步跟踪回去,最终是落在了这个方法
private void runSuitesSequentially(XmlSuite xmlSuite, SuiteRunnerMap suiteRunnerMap, int verbose, String defaultSuiteName) { for (XmlSuite childSuite : xmlSuite.getChildSuites()) { runSuitesSequentially(childSuite, suiteRunnerMap, verbose, defaultSuiteName); } SuiteRunnerWorker srw = new SuiteRunnerWorker(suiteRunnerMap.get(xmlSuite), suiteRunnerMap, verbose, defaultSuiteName); srw.run(); }
最终被入口的run方法调用
里边有非常非常多的细节。但是源码阅读主要在厘清脉络,参考其中优秀的设计。具体的业务细节,可以在遇到问题在详细研究。
这里边其实就是简单的Ioc的应用。面向接口,首先为了保证一个worker对应一个runner,在给worker上线文的时候,本身runner实现了ItestContext接口,然后把自身作为一个参数传给worker。
实现事实上的链式调用。即新开一个runner实例,即会附带新开一个worker实例,这两是一一对应的。这个对多线程编程的场景特别重要。
作为一个测试框架,并发场景主要存在于,参数的准确跟执行的速度足够快,并不存在资源争用、竞争,所以TestNg的这套设计,对于测试工具本身,还是很有启发意义的。
现在来看第二个问题:
测试结果的收集,尤其是多线程下的结果收集。其实在分析完第一个问题,我们已经有结论了。由于避开了资源争用,所以其实在所有的worker执行完之后,所有的结果放在对应的runner里边。在总入口,或者reporter里边,做汇总就可以了。现在来看看我们猜测的是否正确
/** * Run TestNG. */ public void run() { initializeSuitesAndJarFile(); initializeConfiguration(); initializeDefaultListeners(); initializeCommandLineSuites(); initializeCommandLineSuitesParams(); initializeCommandLineSuitesGroups(); sanityCheck(); List<ISuite> suiteRunners = null; runExecutionListeners(true /* start */); m_start = System.currentTimeMillis(); // // Slave mode // if (m_slavefileName != null) { SuiteSlave slave = new SuiteSlave( m_slavefileName, this ); slave.waitForSuites(); } // // Regular mode // else if (m_masterfileName == null) { suiteRunners = runSuitesLocally(); } // // Master mode // else { SuiteDispatcher dispatcher = new SuiteDispatcher(m_masterfileName); suiteRunners = dispatcher.dispatch(getConfiguration(), m_suites, getOutputDirectory(), getTestListeners()); } m_end = System.currentTimeMillis(); runExecutionListeners(false /* finish */); if(null != suiteRunners) { @retinder-->果然,生成报告就是直接用的runner generateReports(suiteRunners); } if(!m_hasTests) { setStatus(HAS_NO_TEST); if (TestRunner.getVerbose() > 1) { System.err.println("[TestNG] No tests found. Nothing was run"); usage(); } } }
结论是,测试结果的汇总并不涉及到多线程。
- testng源码阅读之三
- testng源码阅读之二
- testng源码阅读之四
- testng源码阅读之5
- testng源码阅读之6
- testng源码阅读之读后感
- testng源码阅读之入口在哪
- testng翻译之三--testng.xml
- testng源码阅读之多线程包
- 源码阅读(三)
- pg源码阅读三
- STL源码阅读(三)
- 阅读XRecyclerView源码三
- 从cvLoadImage开始--OpenCV源码阅读之三[转]
- JDK源码阅读之三-----StringBuffer、StringBuilder(未完待续)
- tcmalloc源码阅读(三)---ThreadCache分析之线程局部缓存
- tcmalloc源码阅读(三)---ThreadCache分析之线程局部缓存
- Spark源码阅读笔记之Broadcast(三)
- 商机 | 大数据/政务云采购清单 招标7起,最高招标价为503.9万(11.4-11.7)
- 什么是multipart/form-data请求
- 开源NoSQL数据库:ArangoDB 入门指南
- meituan
- 大数据早报:国产新一代人工智能芯片发布 「龙猫数据」获3370万元A轮融资(11.8)
- testng源码阅读之三
- Blog18@linux关于ftp的介绍
- 【模板】三分法
- 修改jQuery.validate验证方法和提示信息
- nginx重启配置命令
- home/hadoop/tmp/mapred/system/jobtracker.info could only be replicated to 0 nodes, instead of 1问题解决
- Manifest merger failed with multiple errors, see ?
- stellar.js
- 生成密码