1
前言
在前期文章《技术实践干货 | 观远数据 web 自动化框架 Playwright 详解》中,我们分享过使用playwright进行UI自动化,本期想跟大家分享下我们在接口自动化方面的实践。
从测试金字塔模型看,接口测试位于第二层,相比UI自动化,接口会相对稳定一些,而且接口测试既可关注单个接口参数取值的合理性,也可以验证产品功能的完整性和正确性。所以,基于合理的接口设计下,维护一套稳定可用的自动化case是比较理想的方案。
测试金字塔
2
现状分析
随着客户数量越来越多,观远产品目前正在高速发展的阶段,产品版本快速迭代,每月甚至每周都会有一系列的迭代发布,同时业务复杂度也越来越高,随之而来的是大量且不断增多的测试用例,仅BI一条产品线目前就有4000+用例。在每个产品版本发布上线之前,需要做大量的测试工作,包括新需求测试、主干分支测试、回归测试等,同时因为观远是私有化部署模式,所以还需要同时维护多个不同版本的产品,测试工作量就会随之翻倍,业务测试压力可想而知。
以上现状和带来的业务痛点在一定程度上push我们尽快地通过自动化提升人效。接口自动化的投入产出比高,相对「实时」地发现缺陷,同时也能使测试左移,提早发现问题,这也是我们推动测试自动化的理由之一。
3
方案选型
市场有很多的自动化平台/测试工具,目前比较流行的开源自动化框架,如:unittest、JUnit、TestNG、Robot Framework等等。每个框架都有它的优缺点,哪一个是符合我们目前需求的框架呢?我们选择了其中的几种比较有代表性的框架做了一个简单的对比。
框架 | unittest | JUnit | TestNG |
脚本语言 | python | java | java |
用例分类执行 | 可通过@pytest.mark来标记类和方法 | 不支持分组执行用例 | 可通过@group来分组 |
参数化 | 需依赖ddt库 | 使用 @ParameterizedTest 注释 | 利用@Parameter 注释并将参数添加到给定的测试方法 |
断言 | 支持多种断言格式 | 支持多种断言格式 | 支持多种断言格式(assertEqual、assertTrue等等) |
报告 | 使用HTMLTestRunnerNew库 | 以 XML 文件格式提供数据 | 自动生成测试报告 |
失败重跑 | 支持 | 不支持 | 支持 |
并行测试执行 | 不支持 | 支持 | 支持 |
通过参数化、断言、报告等几个维度的对比,可以看出TestNG测试框架在功能上更为强大。它扩展性强、易维护,且自带注释标签、报告、case配置灵活性强。观远目前有多条产品线,TestNG允许我们自定义封装各种协议接口,可以集成各个产品线个性化的项目框架。但原生的TestNG在一些功能上还不是特别能满足我们的需求,比如原生测试报告比较简陋,可读性不高,我们希望能更直观地展示测试版本、通过率、失败详情等信息;原生TestNG只支持通过xml配置分组测试,灵活性不高,而我们需要在不同的需求场景下执行不同优先级用例。所以结合观远业务的实际情况、项目架构及产品技术栈等,我们在此基础上扩展,构建了一套适合观远业务模式的持续集成测试框架。
4
框架介绍
我们先通过一个简单的图来了解下观远持续集成测试框架主要做了哪些事情。
Update Check 前期环境准备:自动维护测试环境,使环境可用且符合测试需求,保证后续的测试执行是正确的。每日自动创建自动化测试执行计划,若当日无代码更新则不执行,减少服务器资源损耗。
API Check 接口监控:每日监控新增的api并通知到责任人,保证接口自动化覆盖率。
API Testing 自动化测试:镜像部署,测试执行,报告整理,消息通知。
以上组成了观远一站式的自动化测试,只需要在jenkins上主动或者自动化发起测试计划,就会根据选择的配置进行测试,直至收到测试报告。下面我们主要来介绍一下核心部分 API Testing。
通过上图可以看出一个case在API testing中被以下模块执行的过程:
jenkins模块:测试同学主动选择测试类型、测试分支及其他可选参数(如优先级等),触发构建动作;也支持定时触发。
用例数据接入模块:获取测试文件中的数据(用例描述、入参、期望、忽略值等等)。同时为了方便管理,以业务模块为准则进行划分,如用户模块、系统设置模块等,各模块数据隔离。
用例执行模块:基于测试数据,对基准数据进行预处理,触发接口请求。
断言模块:获取关键response,提供多样化的断言能力。
报告模块:集成三方插件生成报告,集成jenkins和钉钉能力进行消息通知。
5
实践和探索
有一个技术可行的框架其实只是第一步,我们更注重的是框架的可维护性和易用性,如果日后还需要大量维护工作或者实际开发起来生涩难用,那么也无法提高人效。我们在实际使用时也遇到了一些问题,TestNG框架需要一定的学习成本,大家的代码基础不太一样,对于较薄弱的同学使用还是有一定的难度。为了降低大家的上手成本,观远自动化测试框架在数据接入、断言服务等方面做了一些处理。
模板化的数据接入
实际上在观远BI产品的迭代过程中,基准测试数据的变化,尤其是期望数据的变化还是比较频繁的。很多时候用例失败,可能只是因为接口新增或者删除了一个字段,和接口请求本身没有关系,如果这个时候还需要测试同学深入到代码工程中调试就比较繁琐了。
为了解决类似的问题,我们支持了用文件进行数据接入,目前支持2种测试用例形式:yaml和excel,统一在测试服务器上进行管理。文件中包括用例描述、入参、期望、忽略值等字段值。
通过smb读取文件,整理后以Object[][]格式返回给test类,即为请求入参。
/**
* 主要用于 DataProvider 提供测试用例
*
* @param path
* @return Object[][]
* @throws Exception
*/
public static Object[][] read(String path, InputStream io) throws IOException {
log.info("当前要读取的文件文件名称为:" + path);
Object[][] result = new Object[][]{};
if (path.endsWith(".xlsx")) {
result = ExcelReader.readInputStream(path, io);
} else if (path.endsWith(".yaml")) {
result = YamlUtil.getYamlObject(io);
}
io.close();
if (result == null) {
throw new RuntimeException("获取文件异常");
}
return result;
}
具体的用例执行时,通过TestNG的@DataProvider获取包体信息。
@Test(dataProvider = "dataPro", testName = "XXXXTest", groups = {"P2"})
public void enableUserTest(String description, String parameter, String expected) {
// TODO
smbUtils.read("excel path");
}
当一个用例发生了字段上的改变,只需要修改excel文件内容即可。同时,如果我们需要扩展接口场景,也只需要在excel中新增一条记录,一定程度上降低开发成本。近期,我们同时又开发一个B/S架构的用例管理平台,比文件形式的数据管理更加易用,通过界面交互即可完成用例基准数据的更新,对代码基础薄弱的同学更加友好。
接口请求
执行一个用例之前,往往都要做大量的准备工作,像环境切换、用户登录等。比如用户登录,需要输入域名、用户名、密码,调用登录接口,解析返回包体获取token等一系列操作,这些操作繁琐且重复性高。所以我们将所有的测试类都继承了ApiAbstract父类,父类中使用@BeforeSuite、@AfterSuite注解进行http连接、用户登录、环境版本获取等参数准备,以及接口耗时计算等。后续如果有全量性的需求也方便扩展。
public void setUp() {
client = HttpClientGenerator.getHttpClient();
user = new User(client, re);
auth = new Auth(client, re);
setting = new Setting(client, re);
publicAPI = new PublicAPI(client, re);
Response res1 = auth.signIn(Env.LOGININFO);
// 获取ssotoken登录token
getSsoToken();
// 获取publicapi
getPublicToken();
// 获取server版本号
Env.version = PodServices.getVersion();
}
同时为了减少网络不稳定等的影响,所有测试case接入监听,针对失败的用例重试,若三次后依然失败,则认为存在缺陷或者性能问题。
public class RetryListener implements IAnnotationTransformer{
@Override
public void transform(ITestAnnotation testannotation, Class testClass,
Constructor testConstructor, Method testMethod) {
IRetryAnalyzer retry = testannotation.getRetryAnalyzer();
if (retry == null) {
testannotation.setRetryAnalyzer(Retry.class);
}
}
}
public class RetryTestNGListener extends TestListenerAdapter {
@Override
public void onTestSuccess(ITestResult tr) {
super.onTestSuccess(tr);
// 对于dataProvider的用例,每次成功后,重置Retry次数
Retry retry = (Retry) tr.getMethod().getRetryAnalyzer();
retry.reset();
}
@Override
public void onTestFailure(ITestResult tr) {
super.onTestFailure(tr);
// 对于dataProvider的用例,每次失败后,重置Retry次数
Retry retry = (Retry) tr.getMethod().getRetryAnalyzer();
retry.reset();
}
}
多样化的断言
接口请求完毕后,对返回包体进行断言,这是相当重要的一环。因为产品场景的多样性和不统一性,不同的接口往往在结构上存在很大的差异,这就要求我们针对不同接口有不同的断言处理。
框架里针对观远BI产品中最常见的json格式提供了几种断言方法,比如通过正则表达式校验、结构体包含校验、忽略顺序的结构体校验,主要是jsonPath断言。具体每种断言方式的使用场景和校验逻辑我们会在未来继续做分享。
可快速定位问题的测试报告
测试的目的是保证接口结果的稳定及准确性,当case执行失败时,需要我们快速地定位可能出现问题的原因。目前大多的三方测试报告只会提示部分错误信息或者是错误代码行数,测试同学去确认问题原因时会很耗费时间,有可能还需要重新执行才能确认。
我们在断言结束后,若case结果不符合预期,则抛出异常,还会生成详细的报告。我们对测试报告做了模板化处理,最后的自动化报告内可以看到请求的错误消息以及错误报告,以便研发和测试同学快速定位失败原因。同时,测试case执行完毕后,jenkins脚本会汇总所有测试报告,打包发布至tomcat,方便线上查看、未来回溯。
自动化能力拓展
框架能够使自动化跑起来,但从严格意义上说还不算是可持续集成的框架,自动化执行计划的建立、接口变化的监控、自动化结果的及时跟进等等能力都需要进一步满足。’
打通持续集成到触发自动化环节,自动化对代码提交、新功能发布进行快速验证,建立自动化冒烟测试。自动化执行结果记录保存,包括失败率,执行次数等,便于后续分析质量薄弱点。自动化需要在研发环节的更多阶段发挥作用,持续的对开发提交代码质量进行保证。目前我们已经完成了一部分,并持续地优化:
自动创建自动化测试执行计划,如每日测试、回归测试
每日监控新增的api并通知到责任人,保证接口自动化
测试报告自动发送给责任人并钉钉通知,保存自动化执行结果记录
6
总结
接口自动化已在观远多条产品线实践,在提升回归测试效率、测试左移等方面效果显著。结合jenkins和git,我们建立了自动执行计划,监控接口变化,并及时跟进自动化结果,持续保证产品的质量,更详细的CI/CD实践我们会在未来继续分享。
●●●
👇 点击阅读原文,直接体验Demo
微信扫一扫
关注该公众号