内部wiki版入口:https://wiki.sankuai.com/x/9j9DO
目前Lego由五个不同的项目组成,分别是“测试脚本”、“Lego-web页面项目”、“用于执行接口测试的base包”、“小工具集合Lego-kit”和“lego-job”,各项目间的依赖关系如下图:
本篇文章主要介绍脚本部分:script和base部分。
1. 概述
TestNG+Jenkins 的方式进行自动化测试几乎成了自动化测试的标配,还记得在(1)介绍篇中介绍的,刚开始Lego的组成么:
对的,后来的Lego也还是沿用了这个设计,只不过又略有不同。
现在的“Lego-api-automaition-script等同于原来的“接口自动化测试脚本 jar包”的作用,只是现在script中的内容变的很少,执行接口、校验等动作都放置到了base中。script依赖base这个SNAPSHOT包,这样就算Lego有什么变更或改动,也只需对base包进行更新,不会影响到各组自己的script:
目前,每一个团队都会有自己的一份测试脚本,即script。可以根据自己团队的命名方式命名,上传至code平台,提供给Jenkins随时执行。
下面会我介绍一下这两个脚本的内容。
2.Lego-api-automaction-script
脚本有两块部分,第一块部分是各个业务团队手上的脚本,以“KTV”团队的脚本为例子,打开脚本后,看到的是这样的:
首先注意到的是在src/main/java目录下是空的,只是在test目录下有测试脚本的代码:
原因之前已经说明过了。
test目录中,主要有两种类型的文件:一种是Java文件,一种是Xml文件。
2.1 Java文件
目前接口测试支持的三种接口类型,一种一个Java文件,这个Java文件基本不用改动。这个脚本只需要对Xml进行配置就可以了。
以Pigeon测试用例的class文件为例子:
public class TestServiceApi { String sql; @Parameters({"sql"}) @BeforeClass() public void beforeClass(String sql) { this.sql = sql; } /** * XML中的SQL决定了执行什么用例, 执行多少条用例, SQL的搜索结果为需要测试的测试用例 */ @DataProvider(name = "testData") private Iterator<Object[]> getData() throws SQLException, ClassNotFoundException { return new DataProvider_forDB(TestConfig.DB_IP, TestConfig.DB_PORT, TestConfig.DB_BASE_NAME, TestConfig.DB_USERNAME, TestConfig.DB_PASSWORD, sql); } @Test(dataProvider = "testData") public void test(Map<String, String> data) { new ExecPigeonTest().execTestCase(data, false); } }
这个和很多其他类型的接口自动化测试几乎是一样的,不同的几点是:
- 数据来源为DB。网上的很多解决方案的数据来源为Excel或者Object[][]。
- 具体的执行并没有在这里,而是在依赖的Base包中
所以这个脚本相当于只是一个模板。
同理,Mapi的脚本文件和Http的脚本文件也基本是这些内容,Mapi的执行会多一个白名单的东西,这是由于需要解密解密的过程,我调用qahome中的key list接口进行的解密,难免会有Hash重复对应错的情况,使用白名单可以进行一些替换。
2.2 Xml文件
还是以Pigeon为例子:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Service Api测试" parallel="false"> <test name="tpfun-product-service"> <parameter name="sql" value="SELECT * FROM PigeonCases WHERE team_id=2 AND isRun=1 AND env='beta' AND serviceName='tpfun-xxxx-service';"/> <classes> <class name="com.dp.lego.qatest.apitest.TestServiceApi"/> </classes> </test> <listeners> <listener class-name="org.uncommons.reportng.HTMLReporter"/> <listener class-name="org.uncommons.reportng.JUnitXMLReporter"/> </listeners> </suite>
说明:
- 一个<test>标签,就代表一个测试。
- <parameter>标签的话是传输了一个sql参数至上面的脚本中,sql的动作是查询测试用例。如上面的例子中,在数据库中会查询出下面这56条测试用例,那我这个<test>标签就是执行者56条测试用例。
- <listeners>标签是为了生成最后的ReportNG的报告。
- 可以有多个XML文件,通过命令可以指定需要执行的XML文件(2.3会讲到)。
- 可以存在多个标签,不同的标签会报告的展示中略有不同(2.4会降到)。
很多情况下,大家会吧测试用例直接码在Java文件中,这个其实我一直是不提倡的,这样会导致修改测试用例会改动大量的代码;而且代码不便于交接给其他同学,这类型的自动化交接最后都会变成由下一个同学全部推翻重写一遍;如果测试平台跟换,无法做用例数据的迁移,只能手动的一条条重新输入。
所以“测试数据”与“脚本”分离是非常有必要的。
使用TestNG来进行“测试数据”与“脚本”分离,通常的做法是使用TestNG的@DataProvider注解。
在这里,我的@DataProvider的数据来源是DB,数据源来自DB与Object[][]、Excel相比,会显得更加灵活。
- 使用Object[][]方式的话,需要更新代码,再push到代码平台,如果不小心改错或是按了下键盘多了个字符,又得重新push。
- 使用Excel的话,虽然可能不需要修改到代码,减少了代码误动的风险,但是每次改完Excel再push还是挺繁琐的一个过程。
- 使用DB的话,要修改测试用例的时候只需要对数据库表中某个数据进行修改就行了,不需要动到代码,也无需push操作。
而且在数据库中,多一个如isRun这样的字段,来控制是否需要执行这条测试用例,这样就可以在不改动任何代码和配置文件的前提下,来控制执行测试用例的范围。
2.3 用例执行
- 右键XML文件执行
- 使用maven命令执行测试:mvn clean install -U -Dxml=xmlFileName 通过参数来执行需要执行的xml文件。
2.4 多Test标签时报告展示
XML中,一个<test>标签和多个<test>标签的写法,在执行上,两者是一致的,不同的是在报告的展示上面。
下图就是执行完成后的报告,当有2个<test>标签的话,在左侧会展示2个,3个<test>标签会分成3个超链接,以此类推
上图中,就是一个XML文件中,使用了6个<test>。
3. Lego-api-automaction-base
关于接口自动化测试执行中的所用到的方法,都封装在了这个包中。
代码部分就不一一截图了。
简单介绍一下大概的模块:
3.1 接口自动化测试执行部分
这块就不多做介绍了,就是Pigeon、Mapi、Http三种接口的执行动作。
这三个类都只是对接口做调用的动作,为了统一方便为后面的校验,返回结果统一都是用String类型的json格式。
这样做还有一个好处,如果要接入第四种接口类型(如MTThrift类型),只需要接一个执行接口的类,入参json格式,结果json格式,立马就能然Lego支持这种新的接口类型。
3.2 检查点
除了执行,Base中还有用于结果校验的CheckPoint方法,支持多种校验方式,并固定成模板,(详细的使用会在“用例篇”中介绍)
由3.1讲到的,三种接口类型由于统一了返回结果的类型,所以在检查点上,是可以通用的,省去了针对不同的接口类型、不同的脚本设计不同的校验规则和校验方法的麻烦。
3.3 DataProvider for DB
很早前就写了这个,由于网上更多的是为Excel写的DataProvider实现方法,这里就将我写的这部分贴出来吧,方便给想用DataProvider读取DB数据的同学:
/** * DataProvider for DB * * @author yongda.chen */ public class DataProvider_forDB implements Iterator<Object[]> { ResultSet rs; ResultSetMetaData rd; public DataProvider_forDB(String ip, String port, String baseName, String userName, String password, String sql) throws ClassNotFoundException, SQLException { // 连接数据库 Class.forName("com.mysql.jdbc.Driver"); // 连接数据库 String url = String.format("jdbc:mysql://%s:%s/%s", ip, port, baseName); Connection conn = DriverManager.getConnection(url, userName, password); Statement createStatement = conn.createStatement(); // 执行SQL命令,并返回符合条件的记录 rs = createStatement.executeQuery(sql); rd = rs.getMetaData(); } @Override public boolean hasNext() { boolean flag = false; try { flag = rs.next(); } catch (SQLException e) { e.printStackTrace(); } return flag; } @Override public Object[] next() { Map<String, String> data = new HashMap<String, String>(); try { for (int i = 1; i <= rd.getColumnCount(); i++) { data.put(rd.getColumnName(i), rs.getString(i)); } } catch (SQLException e) { e.printStackTrace(); } Object r[] = new Object[1]; r[0] = data; return r; } @Override public void remove() { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } }
3.4 参数化
四种参数化方式,能支持到替换掉用例中需要替换掉的内容。
如通过数据库获取最新的表单号来用于测试用例中参数的一部分等这样的场景。
也支持一参数修改,所有用例生效的场景。
也支持各种参数化嵌套使用。
3.5 前后置动作
支持五种前后置动作方式,能在用例执行前或执行后,进行一些额外的操作。
3.6 MQ消息发送
字面意思,可以在测试一些接口用例时,发送相应的Swallow或Mafka消息。
4. Q&A
Q: 既然Script中只有xml比较重要,是不是Script可以省略掉了?
A: 理论上,的确只是需要xml里的sql就行了,但是目前我并不想将Script省略掉,而是还保留这样一个TestNG+Jenkins的脚本。主要考虑到下面一些原因:
- 担心省略掉后,一些新来的校招生等同学会忽略掉这部分内容。就像很多公司封装的很好的工具,一些同学用的时候用的很好,离职的时候发现连怎么实现的都不知道;
- 保留Script可以让一些团队可以定制自己的sql和report的展示;
- 保留Script可以让一些团队根据自己的需要,开发一些如数据处理、数据存储等偏自己部门特色的功能;
- 保留Script可以让一些团队根据自己的需要,开发一些如数据处理、功能实现等功能,弥补一些Lego目前不支持的功能。
如果后面我将Lego开源,会省略掉这部分操作。
Q:为什么还要使用Jenkins来驱动执行?既然还有个对应的web项目,是不是连这部分也可以自己开发了?
A:开发掉不难,但是考虑到以下几个方面,还是沿用了Jenkins:
- 目前我还是业务线的QA,并没有全天开发的时间,所以考虑到开发和后面的维护的成本,还是选用现有且成熟的方案更为理想;
- 公司的构建也是使用了Jenkins的方案,从平台到Slave都会有专门的人员进行维护;
- 便于采集数据,后面web项目中,我也使用了Jenkins Api进行执行结果数据的采集,同时,公司也会对CI上的数据进行采集,如果自己开发,很显然公司层面就采集不到数据,公司也不会来接QA的一个测试项目,肯定是希望QA能使用公司提供的一些公共平台;
- 自带邮件服务;
- 自带公司通讯工具大象插件;
- 足够的在线报告存储空间;
- 无缝接入代码覆盖率获取;
- 可以直接使用由公司工具组开发的功能,实现构建完成后执行对应接口测试用例。
好啦~脚本篇结束,有什么问题可以直接给本公众号发消息或在本站留言。
nbsp;
陈老师,
这个Lego平台只是用来测接口吗?UI本身的功能可以用Lego测吗?另外,贵司是不是还有其他的自动化测试工具/平台?
目前来说,只是做接口测试,其他类型的测试会有其他的平台,也没有必要做个大而全的东西嘛。
然后公司内是很大的,每个业务线都会有自己做的相关工具,当然也可以用别的团队现有的工具。
所以目前我这工具会支持一些别的团队的同学使用。
如果还是要用jenkins+testNG,那根不用平台有啥区别,做平台的目的不就是帮大家省略掉开发测试脚本,大家只需要在平台上维护接口和数据,让平台来集成执行,是这样吗?
首先,我不用再开发测试脚本了,我有写的,第一次配置一下而已,脚本是空的,不用再编写脚本,只是用了TestNG+Jenkins。
测试用例怎么执行本身不是重点,维护的是数据,所以web的任务就是缩短维护时间,用过就知道了,完全感知不到还有个TestNG的脚本存在。
使用maven命令执行测试:mvn clean install -U -Dxml=xmlFileName 通过参数来执行需要执行的xml文件。 你这命令是在哪执行的,是在java代码里边执行cmd命令吗,还是手动执行?
可以是cmd,也可以是Jenkins的构建
老师,你的接口平台还是需要写用例脚本吗?
不用code