写在前面
本文我们一起来学习如何使用Robot Framework 的RequestsLibrary库,涉及POST、GET接口测试,RF用例分层封装设计等内容。
接口
接口测试是我们最常见的测试类型之一,主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。--摘自百度百科
RequestsLibrary
RequestsLibrary是基于reuqests库定义的一个Robot Framework 库。requests就不用介绍了吧,GitHub上面超过36k star的超级Python项目。
安装
pip install requests
pip install robotframework-requests
简单使用
*** Settings ***
Documentation http请求Demo
Library Collections
Library RequestsLibrary
*** Variables ***
${host} http://httpbin.org
*** Test Cases ***
Post 请求Demo
[Tags] Post main
${data} Create Dictionary name=Detector age=18
create session httpbin ${host}
${response} post request httpbin /post params=${data}
should be equal as integers ${response.status_code} 200
${resp} to json ${response.content}
should not be empty ${resp["args"]}
dictionary should contain key ${resp["headers"]} Host
dictionary should contain value ${resp["headers"]} httpbin.org
Get 请求Demo
[Tags] Get
${data} Create Dictionary name=Detector age=18
create session httpbin ${host}
${response} get request httpbin /get params=${data}
should be equal as integers ${response.status_code} 200
${resp} to json ${response.content}
should not be empty ${resp["args"]}
dictionary should contain key ${resp["headers"]} Host
dictionary should contain value ${resp["headers"]} httpbin.org
上面这是一个简单的Demo,我们在*** Settings ***
中引入了标准库Collections
和刚安装的RequestsLibrary
,在*** Variables ***
中定义了全局变量${host}
。
然后开始写测试用例了,以Post 请求Demo
为例,我们一起来看看用例里面包含了些什么:
第一行:我们给当前用例指定了Tag,一个用例是可以指定多个Tag的,非常灵活,用法我们在前一篇中有介绍
第二行:我们创建了一个一个字典并赋值给了变量${data}
,作为后续的数据传入
第三行:我们创建了一个HTTP会话,并给它取了一个别名httpbin
第四行:我们根据根据前一行创建的会话别名查找会话,并在会话中发送POST请求
第五行:我们对接口的接口的结果码进行了断言,因为RF所有的数据都是以字符串方式存储的,所以使用将should be equal as integers
把他们作为int
进行比较
第六行:我们将接口响应的内容使用RequestsLibrary库的关键字to json
转化为了JSON
第七行:我们对转化后的JSON的的args数据进行了不能为空的断言
第八行:我们使用Collections
的dictionary should contain key
关键字对返回数据headers中是否含有Host进行了断言
第九行:我们对返回数据的headers中Host字段的值进行了断言
注: 在RF中,单条用例某个步骤执行失败,后续步骤在没有做特殊配置的情况下 都会略过不执行。
分层封装(数据驱动测试)
上面的示例中写了两个测试用例,除了因为要体现GET
、POST
外还有另外一个作用,那就是引出分层封装。细心的伙伴可能已经注意到了:我们两个用例有很多一样的操作。
根据一个功能如果需要重复使用两次以上就应该抽象成一个独立的函数的原则,特别当我们有多个用例都是使用同样的操作,只是每次输入的参数不一样的时候,我们应该把公共操作独立出来。
这个封装的操作在RF中有两种实现方式:
- 在Robot用例文件中直接封装
- 自定义函数,实现相关功能的关键字进行调用
我们今天介绍第一种,第二种方式我们会在介绍如何自定义关键字的时候介绍。
简单封装
我们先来看看简单的封装的例子,仅对请求的和数据转化的细节进行封装,这种方式在扩展的时候非常灵活:
*** Test Cases ***
Package Post
[Tags] packaged req
${data} Create Dictionary name=Detector age=18
${resp} POST Req ${data}
should not be empty ${resp["args"]}
dictionary should contain key ${resp["headers"]} Host
dictionary should contain value ${resp["headers"]} httpbin.org
*** Keywords ***
POST Req
[Arguments] ${data}
Create Session api ${host}
${response} Post Request api /post params=${data}
should be equal as integers ${response.status_code} 200
${resp} to json ${response.content}
[Return] ${resp}
可以看到,我们通过*** Keywords ***
定义了关键字POST Req
,定义过程中分别使用[Arguments]
、[Return]
来接收和返回的数据。
POST Req
中整合了创建HTTP会话,转化接口返回结果等步骤,,调用和其他的RF库自带关键字没有什么区别。
高度封装
我们再来看看高度封装,这种方式会将所有的细节全部封装,优点是用例简洁,只保留传入参数和预期结果,缺点是灵活性低,不易扩展:
*** Test Cases ***
packaged test
[Template] Packaged POST Req
name host Content-Length=0
name host name Content-Length=0
*** Keywords ***
Packaged POST Req
[Arguments] ${data} ${Hosts} @{args} &{HostValue}
Create Session api ${host}
${response} Post Request api /post params=${data}
should be equal as integers ${response.status_code} 200
${resp} to json ${response.content}
# log ${resp}
dictionary_should_contain_sub_dictionary ${resp["headers"]} ${HostValue}
run keyword if ${args} log ${args}
... ELSE should not be empty ${resp["args"]}
*** Keywords ***
解析:
第一行: 我们定义了Packaged POST Req
能接受的参数,可选参数:@{args}
、&{HostValue}
与Python中*args
、**args
对应;
第六行: 我们使用了新的关键字dictionary_should_contain_sub_dictionary
来断言字典包含场景;
第七行: 我们使用了新的关键字run keyword if
来判断${args}
是否为空,然后根据这个条件作出不同的操作。
运行上面的用例查看测试报告,可以看到packaged test
这一个用例其实在内部运行了两次。分别覆盖了@{args}
是否为空的情况。
在实际编写用例的过程中,建议两种方式组合使用,响应参数简单的使用第二种方式,响应参数复杂度较高的使用第一种,方便灵活扩展。
总结
- RequestsLibrary 库的安装使用
- 数据驱动测试(分层用例封装)