1. 实际应用概述
Jabber是一个基于开源XMPP协议的企业级即时通讯架构,它的典型商业应用为思科Jabber服务,其为沃尔玛、通用等300多万客户提供企业通讯服务。 而基于TestNG的针对Jabber的实时监控工具,也已经成功应用于基于Jabber的大型企业级产品线上,为这个世界的沟通,贡献力量。
2. 设计思想概述:
针对实际问题,去选用适当的方法 —— 这里仅引用 @项目管理智汇团2014年6月21日的新浪微博:在“寻找解决方案时,记住要从问题出发,而不要从特定的实现方法出发。具体来说,要寻找: 源代码控制工具,而不是SVN; 快速应用程序开发手段,而不是Rubyon Rails;富Internet应用开发框架,而不是Flex;对象关系映射库,而不是Hibernate。”
而这里讨论的实际问题,是在大规模分布式架构的产品线上,如何“稳定、快速、精确的发现和定位某个故障组件”这个实际问题。我们将这个问题分解为1)快速设计测试Case 2)精确定位故障 3)稳定运行
1) 快速设计测试Case:这里笔者所在的测试团队选择TestNG……
a. 比较同样大名鼎鼎的JUnit,TestNG虽然出现较晚,但是却能够包容JUnit的优点和补充JUnit在细化的功能测试方面的不足。尤其是它扩展了JavaAnnotation, 从而使它能提供的针对测试的Annotation十分丰富,如@BeforeSuite@BeforeTest 等等,用这些Annotation作为“积木”来搭建测试Case很快捷。
b. 笔者所在的产品开发敏捷团队,在做产线监控前端的功能测试时,使用的就是TestNG。“我们要站在巨人的肩膀上”,所以运用TestNG将功能测试Case中的典型Case提取出来,成为监控Case,顺理成章。
c. TestNG的Report类,笔者感觉定制起来也很快捷,这里将在3.2小节中详细叙述。
2) 精确定位故障:利用STAF或cron 这一Linux的内置服务,来分别启动针对不同产线组件的监控程序。这是典型的“分治法”——“就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。”(分治法定义——摘自搜狗百科)
落实到这里阐述的案例,即每个监控子程序(后面会表述为测试PlugIn),只负责它所测试的特定产线的特定组件,而调度程序将这些子测试结果进行汇总,才达成对整个产线集群的完整监控。
3) 稳定运行
a. 前后端分离,利用稳定的后台service来管理监督各个监控子程序的运行, 前端则负责人机界面和测试PlugIn管理。
b. 利用前端的Html页面+Tomcat server进行各个测试PlugIn的插入和管理——即Management Server。
c. 后端的Staf server利用STAF进行自动化测试分布式运行 (可参考http://www.cnblogs.com/zhangfei/archive/2013/07/03/3169139.html-- 《如何用STAF进行自动化测试分布式运行 》)
d. 后台service和前端server,它们都采用hot standby模式,即1台server挂掉之后,第2台server会接替第1台的管理工作。
这里仅给出Tomcat cluster的冗余配置方法供大家参考:具体可参看 http://tomcat.apache.org/connectors-doc/generic_howto/loadbalancers.html中的“configure hot spare workers”
下面是简单的设计框架:
3. 具体实现技术概述
3.1 将TestNG的测试suite组装成3.3中STAF可执行的jar文件:
具体 如何利用TestNG来组装包含业务逻辑的实际测试case,这在网上有很多blog和资料可供查询,这里就不累述。在本案例中,笔者重点说的是如何来利用maven的assembly生成可执行jar的技巧:
1. 需要在maven的 pom.xml 中的< plugins > node中,定义:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>exe.xml</descriptor>
</descriptors>
<archive>
<manifestFile>META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
2. 需要定义相应的 maven goal 为:
clean assembly:assembly
3. 在exe.xml文件中,定义assembly的参数:
<assembly>
<id>exe</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory></outputDirectory>
<outputFileNameMapping></outputFileNameMapping>
<unpack>true</unpack>
<scope>runtime</scope>
<includes>
</includes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>target/classes</directory>
<outputDirectory></outputDirectory>
</fileSet>
</fileSets>
</assembly>
4. 在MANIFEST.MF中,定义该maven项目的主执行类
Main-Class: com.taotao.jabber.cases.MctJarMain
5. 以下是这几个configuration文件的具体位置:
6. 建立一个主程序即com.taotao.jabber.cases.MctJarMain来装载和运行所有的TestNGTest Suite :
public class MctJarMain { public static void main(String[] args) throws IOException { TestNG tng=new TestNG(); tng.setOutputDirectory("./testngResult"); List<Class> listnerClasses = new ArrayList<Class>(); listnerClasses.add(CustomReporter.class); tng.setListenerClasses(listnerClasses); Class[] classArray = {com.taotao.jabber.cases.TestPresence.class } ; for(int i = 0 ; i< classArray.length ; i ++){ tng.setTestClasses( new Class[]{ classArray[i] } ) ; tng.run(); } }
上述的这个方法,笔者基本上参考了http://left.subtree.org/2008/01/24/creating-executable-jars-with-maven/,如果大家在dependencySets中需要更深入的定制的话,可以进一步查阅。
3.2 定制Report类:
在主程序中,我们用到了CustomReporter这个类,它的作用是在所有TestSuite执行完成后,来对每个组件测试的结果,进行归纳总结。
它的重要输入参数是suites,所有测试后产生的测试结果等信息,都存储在这个List中:
public class CustomReporter implements IReporter{ @Override public void generateReport(List xmlSuites, List suites, String outputDirectory) { ISuite suite = (ISuite) suites.get(0) ; for( ISuiteResult result : suite.getResults().values()){ ITestContext context = result.getTestContext(); IResultMap passedTests = context.getPassedTests(); IResultMap failedTests = context.getFailedTests(); IResultMap failedConfigurations = context.getFailedConfigurations(); // Similar to if(failedConfigurations.size() > 0 ){...} if(failedTests.size() > 0 ){ // Print all test stackTrace etc.... for( ITestResult r: failedTests.getAllResults()) { printOutErrorDetails(r) ; } exit(1) ; } } } }
3.3利用STAF将每个独立的测试Plugin组装起来:
最后,我们简单介绍一下STAF在项目中的运用——STAF在这个测试系统中,扮演了 “胶水” 的角色,从而使针对各产品组件的分布式的定时测试成为可能:
1) 利用STAF的监控功能,看管每个测试Plugin所触发的测试jar的进程
2) 利用STAF的定时启动功能,定时触发每个测试Plugin并及时查看测试结果
3) 利用STAF的文件获取功能,查看某个特定的失败了的测试Plugin测试过程的相应log…
讲完,希望本博客中的设计思想和技术细节,对大家的学习和工作有所裨益。
觉得好您就点赞,帮助笔者赢取此次“CSDN博客大赛的奖金”。我夏天里的每一根“巧乐滋生”,都源于您的爱!