maxelliot 2020-06-21
为了更好的了解自动化测试框架,我们先从自动化测试的发展历程说起;一般测试工作限在3年以上且接触过自动化测试的应该对以下几种自动化测试框架思想有一定的认知:
模块化思想
库思想
数据驱动思想
关键字驱动思想
以上仅仅是代表了一种自动化测试的思想,并不能定义为框架。上面讲到框架=思想+方法,于是演化了以下五种框架:
需要创建小而独立的可以描述的模块、片断以及待测应用程序的脚本。这些树状结构的小脚本组合起来,就能组成能用于特定的测试用例的脚本。
与模块化测试脚本框架很类似,并且具有同样的优点。不同的是测试库框架把待测应用程序分解为过程和函数而不是脚本。这个框架需要创建描述模块、片断以及待测应用程序的功能库文件。
这个框架需要开发数据表和关键字。这些数据表和关键字独立于执行它们的测试自动化工具,并可以用来“驱动"待测应用程序和数据的测试脚本代码,关键宇驱动测试看上去与手工测试用例很类似。在一个关键字驱动测试中,把待测应用程序的功能和每个测试的执行步骤一起写到一个表中。
这个测试框架可以通过很少的代码来产生大量的测试用例。同样的代码在用数据表来产生各个测试用例的同时被复用。
在这里测试的输入和输出数据是从数据文件中读取(数据池,ODBC源,CSV文件,EXCEL文件,Json文件,Yaml文件,ADO对象等)并且通过捕获工具生成或者手工生成的代码脚本被载入到变量中。在这个框架中,变量不仅被用来存放输入值还被用来存放输出的验证值。整个程序中,测试脚本来读取数值文件,记载测试状态和信息。这类似于表驱动测试,在表驱动测 试中,它的测试用例是包含在数据文件而不是在脚本中,对于数据而言,脚本仅仅是一个“驱动器”,或者是一个传送机构。然而,数据驱动测试不同于表驱动测试,尽管导航数据并不包含在表结构中。在数据驱动测试中,数据文件中只包含测试数据。
最普遍的执行框架是上面介绍的所有技术的一个结合,取其长处,弥补其不足。这个混合测试框架是由大部分框架随着时间并经过若干项目演化而来的。
设计出来的框架是直接给测试人员,而且其他的测试人员只需要简单的向里面不断的补充测试用例即可;所以我们的框架设计必须三简化即操作简单,维护简单,扩展简单。
设计框架的同时一定要结合业务流程,而且不仅仅靠技术实现,其实技术实现不难,难点对业务流程的理解和把握。
设计框架时要将基础的封装成公用的,如:get请求、post请求和断言封装成同基础通用类。
测试用例要与代码分享,这样便于用例管理,所以将我们选择上面的数据驱动思想。
工具 | 学习 成本 | 录制 | 持续集成 | 测试报告 | 用例管理 | 性能测试 | 扩展难度 | 最低要求 |
---|---|---|---|---|---|---|---|---|
Java+testng+Maven | 高 | 否 | 是 | 是 | 难 | 是 | 中 | Java |
Requests+Python | 低 | 否 | 是 | 是 | 难 | 是 | 中 | Python |
Robot Framework | 低 | 否 | 是 | 是 | 易 | 否 | 高 | 工具组件 |
HttpRunner | 低 | 是 | 是 | 是 | 易 | 是 | 低 | Python |
Python的Requests库针对所有的HTTP请求方法,采用的是统一的接口
requests.request(method, url, **kwargs)
其中,kwargs可以保护HTTP请求所有可能用到的信息,例如:headers、cookies、params、data、auth等。所以,只要遵循Requests的参数规范,在接口测试用例中复用Requests参数的概念即可。而HttpRunner处理逻辑很简单,直接读取测试用例中的各项参数,传递给Requests发起请求。
1)Requests接口请求示例
<span>def <span><span>test_login<span>(<span>self<span>)<span>:</span></span></span></span></span></span></span>
<span><span><span><span><span><span><span> url <span>= <span>"www.xxx.com/api/users/login"</span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span> data <span>= <span>{
</span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span> <span>"name"<span>: <span>"user1"<span>,</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span> <span>"password"<span>: <span>"123456"</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span> <span>}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span> resp <span>= requests<span>.post<span>(url<span>, json<span>=data<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span> <span>self<span>.assertEqual<span>(<span>200<span>, resp<span>.status_code<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
<span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span><span> <span>self<span>.assertEqual<span>(<span>True<span>, resp<span>.json<span>(<span>)<span>[<span>"success"<span>]<span>)</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>
这样的用例在实际项目中会存在两个问题:
用例模式基本固定,会存在大量相似或重复的用例,用例维护有很大问题
用例与执行代码不分离,参数数据也未分离,同样不易维护
2)HttpRunner使用json/yaml格式处理测试用例,分离后的用例描述如下
{ "name": "test login", "request": { "url": "www.xxx.com/api/users/login", "method": "POST", "headers": { "content-type": "application/json" }, "json": { "name": "user1", "password": "123456" } }, "response": { "status_code": 200, "headers": { "Content-Type": "application/json" }, "body": { "success": true, "msg": "user login successfully." } } }
def run_testcase(testcase): req_kwargs = testcase[‘request‘]try: url = req_kwargs.pop(‘url‘) method = req_kwargs.pop(‘method‘) except KeyError: raise exception.ParamsError("Params Error") resp_obj = requests.request(url=url, method=method, **req_kwargs) diff_content = utils.diff_response(resp_obj, testcase[‘response‘]) success = False if diff_content else True return success, diff_content 4)从测试用例中获取HTTP接口请求参数,testcase[‘request‘] { "url": "www.xxx.com/api/users/login", "method": "POST", "headers": { "content-type": "application/json" }, "json": { "name": "user1", "password": "123456" } } 5)发起Http请求 requests.request(url=url, method=method, **req_kwargs) 6)检测测试结果,即断言 utils.diff_response(resp_obj, testcase[‘response‘])
根据简单易用易维护原则我们使用HttpRunner工具设计框架。
主要特性:
集成了Requests的全部特性,满足对http、https的各种测试需求
测试用例与代码分离,采用YAML/JSON的形式描述测试场景,保障测试用例具备可维护性
测试用例支持参数化和数据驱动机制
基于 HAR 实现接口录制和用例生成功能
结合 Locust 框架,无需额外的工作即可实现分布式性能测试
执行方式采用 CLI 调用,可与 Jenkins 等持续集成工具完美结合
测试结果统计报告简洁清晰,附带详尽统计信息和日志记录
具有可扩展性,便于扩展实现 Web 平台化
2、环境准备
安装HomeBrew(MacOs软件包管理工具,类似apt-get、yum)
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install pyenv echo ‘export PYENV_ROOT="$HOME/.pyenv"‘ >> ~/.bash_profile echo ‘export PATH="$PYENV_ROOT/bin:$PATH"‘ >> ~/.bash_profile echo ‘eval "$(pyenv init -)"‘ >> ~/.bash_profile exec $SHELL -l
pyenv install --list //查看可安装的Python版本 pyenv install 3.6.0 //安装3.6.0版本 pyenv rehash //更新pyenv pyenv versions //查看已经安装的python版本,带*号的是当前使用的版本
pyenv global 3.6.0 //设置全局版本,即当前系统使用的版本将切换为3.6.0
pip install httprunner //运行如下命令,若正常显示版本号,则说明httprunner安装成功: hrun -V 0.9.8
至此HttpRunner已搭建完成
在HttpRunner中,测试用例引擎最大的特色就是支持Yaml/Json格式的用例描述形式;
采用YAML/JSON格式编写维护测试用例,优势还是很明显的:
相比于表格形式,具有更加强大的灵活性和更丰富的信息承载能力;
相比于代码形式,减少了不必要的编程语言语法重复,并最大化地统一了用例描述形式,提高了用例的可维护性。
Yaml格式
Json格式
以下以数澜--数栖平台2.X中的研发平台为例(采取Json格式)
场景:项目空间后,需要快速支持创建Demo示例,即自动创建各种目录和任务。
1)确定业务流程所使用到的接口并通过Postman或Jmeter调试通过及分好类
查询类(Get请求)接口:查询任务目录、查询资源组、查询工作流等
新增类(Post请求)接口:新建目录、新建任务等
2)根据业务流程确定接口顺序
3)向Json文件里按照规则填写接口相关信息
接口Base_Url
接口路径
接口请求方式
接口请求参数
接口断言
接口返回参数(关联接口时会用到上一接口返回的参数)
以下是部分用例示例
4)用例填写完成后,执行用例文件,如Json文件为task.json
hrun task.json
5)查看运行结果
在此目录下会自动生成一个reports文件,进入该文件夹可看到生成带时间的html(执行一次就会生成一个Html文件)
打开此Html查看
全部通过
部分通过
点击trackback可查看定位错误信息
欢迎大家加入软件测试交流群1125760266~一起学习交流!