背景
这两天从测试组同事那里发现,自己的bug总能被他们抓到,仿佛有如神助,问了下发现他们用了robotframework来定期跑我们的接口,然后就这样,bug再也藏不住了。被发现了还能怎么办,改bug呗。
但是改bug不是目的,有bug说明自测不到位,需要反思下自己的代码准确性。光靠自测有时候可能发现不了边界值等问题,往往都是自测一下发现有数据了,开发的工作就算完事了,但是实际上,这还远远不够。
TDD(测试驱动开发)是一个不错的指导,继代码REVIEW之后的另一个提升程序质量的强力手段。
配环境
于是就开始搜怎么用这玩意儿了,发现一个不错的链接,对入们来说还算可以。通过实例学习robotframework 有兴趣的可以瞅一瞅,瞄两眼。
官网的链接就我的英语水平,还不能完全hold住,最快的学习方然还是通过实例啦。于是搞到了测试同事明大佬的代码,修修补补,缝缝改改,先跑通再说。
运行环境
在这之前,当然还是先配下环境,robotframework基于咱的老本行Python,那就没的说了。
pip install requests
pip install robotframework
pip install robotframework-requests
这里只是拿来做黑盒(接口)测试,因此requests就够了。同样对于robotframework也需要装一下robotframework-requests。
编码环境
一开始是VIM写,结果没有关键字提示,写起来很费劲,因为根本不知道哪里忘了打空格,所以就换了IDE,没有用ride.py,因为不想装wxpython。就再pycharm上装了robotframework的插件intellibot和robotframework support, 重启后把TXT格式的映射到对应的编辑环境上,就完事了。
配好环境就算是磨好了砍柴的刀,剩下的写一写测试用例就可以了。在开始之前,需要注意一下几点:
- 开头设置好引用的库,具体写到
*** Settings ***
, 注意空格和字符*
的个数与格式。 - 全局变量,定义在
*** Variables ***
下面,格式为${variablename} variablevalue
注意中间有俩空格,当然这里空格的个数不做强制性的要求。 - 测试用例定义在
*** Test Cases ***
, 注意空格和*
之间的格式即可。 - 测试用例内部,一般有如下步骤: 准备参数, 执行动作, 获取返回结果并进行断言。
*** Settings ***
Library RequestsLibrary
Library Collections
Library String
Library OperatingSystem
*** Variables ***
${domain} http://api.xxxx.com
${version} 2.5.0
${curuserid} 2614677
*** Test Cases ***
个人信息修改_设置个人信息_setuserinfo
[Documentation] 修改昵称,修改性别,修改签名等
${ac} set variable setuserinfo
${nickname} set variable 太阳宫李荣浩
${type} set variable nickname
create session sessionname ${domain} verify=True
${params} create dictionary xxx=${xxx} ac=${ac} curuserid=${curuserid} nickname=${nickname} type=${type}
${response} get request sessionname /api params=${params}
${jsondata} to json ${response.content} pretty_print=True
log 返回状态码${response.status_code}
log 返回的errorcode ${response.json()['errorcode']}
log ------断言部分-------
should be equal as numbers ${response.status_code} 200
should be equal as strings ${response.json()['errorcode']} ok
should be equal as strings ${response.json()['result']['nickname']} 太阳宫李荣浩
这个测试文件里面只写了一个测试用例,其实还可以写成多个测试用例,到时候就可以批量跑。
跑起来
将上面的代码保存为api.robot,然后就可以跑测试用例了。
➜ robottest robot api.robot
==============================================================================
Api
==============================================================================
个人信息修改_设置个人信息_setuserinfo :: 修改昵称,修改性别,修改... | PASS |
------------------------------------------------------------------------------
Api | PASS |
1 critical test, 1 passed, 0 failed
1 test total, 1 passed, 0 failed
==============================================================================
Output: /Users/biao/PycharmProjects/robottest/output.xml
Log: /Users/biao/PycharmProjects/robottest/log.html
Report: /Users/biao/PycharmProjects/robottest/report.html
➜ robottest
提升
刚才只是一个简单的小例子,实际上我们的接口可能会有多种场景,光靠这点是远远不够的,还好官网给了几个不赖的demo,拿来改一改,差不多就可以应付了。
*** Settings ***
Library Collections
Library String
Library ../src/RequestsLibrary/RequestsKeywords.py
Library OperatingSystem
Suite Teardown Delete All Sessions
*** Test Cases ***
Get Requests
[Tags] get
Create Session google http://www.google.com
Create Session github https://api.github.com
${resp}= Get Request google /
Should Be Equal As Strings ${resp.status_code} 200
${resp}= Get Request github /users/bulkan
Should Be Equal As Strings ${resp.status_code} 200
Dictionary Should Contain Value ${resp.json()} Bulkan Evcimen
Get Requests with Url Parameters
[Tags] get
Create Session httpbin http://httpbin.org
&{params}= Create Dictionary key=value key2=value2
${resp}= Get Request httpbin /get params=${params}
Should Be Equal As Strings ${resp.status_code} 200
${jsondata}= To Json ${resp.content}
Should be Equal ${jsondata['args']} ${params}
Get Requests with Json Data
[Tags] get
Create Session httpbin http://httpbin.org
&{data}= Create Dictionary latitude=30.496346 longitude=-87.640356
${resp}= Get Request httpbin /get json=${data}
Should Be Equal As Strings ${resp.status_code} 200
${jsondata}= To Json ${resp.content}
Should Be Equal As Strings ${resp.status_code} 200
Get HTTPS & Verify Cert
[Tags] get
Create Session httpbin https://httpbin.org verify=True
${resp}= Get Request httpbin /get
Should Be Equal As Strings ${resp.status_code} 200
Get HTTPS & Verify Cert with a CA bundle
[Tags] get
Create Session httpbin https://httpbin.org verify=${CURDIR}${/}cacert.pem
${resp}= Get Request httpbin /get
Should Be Equal As Strings ${resp.status_code} 200
Get With Auth
[Tags] get
${auth}= Create List user passwd
Create Session httpbin https://httpbin.org auth=${auth}
${resp}= Get Request httpbin /basic-auth/user/passwd
Should Be Equal As Strings ${resp.status_code} 200
Should Be Equal As Strings ${resp.json()['authenticated']} True
Get With Digest Auth
[Tags] get
${auth}= Create List user pass
Create Digest Session httpbin https://httpbin.org auth=${auth} debug=3
${resp}= Get Request httpbin /digest-auth/auth/user/pass
Should Be Equal As Strings ${resp.status_code} 200
Should Be Equal As Strings ${resp.json()['authenticated']} True
Post Request With URL Params
[Tags] post
Create Session httpbin http://httpbin.org
&{params}= Create Dictionary key=value key2=value2
${resp}= Post Request httpbin /post params=${params}
Should Be Equal As Strings ${resp.status_code} 200
Post Request With No Data
[Tags] post
Create Session httpbin http://httpbin.org
${resp}= Post Request httpbin /post
Should Be Equal As Strings ${resp.status_code} 200
Put Request With No Data
[Tags] put
Create Session httpbin http://httpbin.org
${resp}= Put Request httpbin /put
Should Be Equal As Strings ${resp.status_code} 200
Post Request With No Dictionary
[Tags] post
Create Session httpbin http://httpbin.org debug=3
Set Test Variable ${data} some content
${resp}= Post Request httpbin /post data=${data}
Should Be Equal As Strings ${resp.status_code} 200
Should Contain ${resp.text} ${data}
Put Request With URL Params
[Tags] put
Create Session httpbin http://httpbin.org
&{params}= Create Dictionary key=value key2=value2
${resp}= Put Request httpbin /put params=${params}
Should Be Equal As Strings ${resp.status_code} 200
Put Request With No Dictionary
[Tags] put
Create Session httpbin http://httpbin.org
Set Test Variable ${data} some content
${resp}= Put Request httpbin /put data=${data}
Should Be Equal As Strings ${resp.status_code} 200
Should Contain ${resp.text} ${data}
Post Requests
[Tags] post
Create Session httpbin http://httpbin.org
&{data}= Create Dictionary name=bulkan surname=evcimen
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Post Request httpbin /post data=${data} headers=${headers}
Dictionary Should Contain Value ${resp.json()['form']} bulkan
Dictionary Should Contain Value ${resp.json()['form']} evcimen
Post With Unicode Data
[Tags] post
Create Session httpbin http://httpbin.org debug=3
&{data}= Create Dictionary name=度假村
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Post Request httpbin /post data=${data} headers=${headers}
Dictionary Should Contain Value ${resp.json()['form']} 度假村
Post Request With Unicode Data
[Tags] post
Create Session httpbin http://httpbin.org debug=3
&{data}= Create Dictionary name=度假村
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Post Request httpbin /post data=${data} headers=${headers}
Dictionary Should Contain Value ${resp.json()['form']} 度假村
Post Request With Binary Data in Dictionary
[Tags] post
Create Session httpbin http://httpbin.org debug=3
${file_data}= Get Binary File ${CURDIR}${/}data.json
&{data}= Create Dictionary name=${file_data.strip()}
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Post Request httpbin /post data=${data} headers=${headers}
Log ${resp.json()['form']}
Should Contain ${resp.json()['form']['name']} \u5ea6\u5047\u6751
Post Request With Binary Data
[Tags] post
Create Session httpbin http://httpbin.org debug=3
${data}= Get Binary File ${CURDIR}${/}data.json
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Post Request httpbin /post data=${data} headers=${headers}
Log ${resp.json()['form']}
${value}= evaluate list(${resp.json()}['form'].keys())[0]
Should Contain ${value} 度假村
Post Request With Arbitrary Binary Data
[Tags] post
Create Session httpbin http://httpbin.org debug=3
${data}= Get Binary File ${CURDIR}${/}randombytes.bin
&{headers}= Create Dictionary Content-Type=application/octet-stream Accept=application/octet-stream
${resp}= Post Request httpbin /post data=${data} headers=&{headers}
# TODO Compare binaries. Content is json with base64 encoded data
Log "Success"
Post With File
[Tags] post
Create Session httpbin http://httpbin.org
${file_data}= Get Binary File ${CURDIR}${/}data.json
&{files}= Create Dictionary file=${file_data}
${resp}= Post Request httpbin /post files=${files}
${file}= To Json ${resp.json()['files']['file']}
Dictionary Should Contain Key ${file} one
Dictionary Should Contain Key ${file} two
Post Request With File
[Tags] post
Create Session httpbin http://httpbin.org
${file_data}= Get Binary File ${CURDIR}${/}data.json
&{files}= Create Dictionary file=${file_data}
${resp}= Post Request httpbin /post files=${files}
${file}= To Json ${resp.json()['files']['file']}
Dictionary Should Contain Key ${file} one
Dictionary Should Contain Key ${file} two
Post Request With Data and File
[Tags] post
Create Session httpbin http://httpbin.org
&{data}= Create Dictionary name=mallikarjunarao surname=kosuri
Create File foobar.txt content=foobar
${file_data}= Get File foobar.txt
&{files}= Create Dictionary file=${file_data}
${resp}= Post Request httpbin /post files=${files} data=${data}
Should Be Equal As Strings ${resp.status_code} 200
Put Requests
[Tags] put
Create Session httpbin http://httpbin.org
&{data}= Create Dictionary name=bulkan surname=evcimen
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Put Request httpbin /put data=${data} headers=${headers}
Dictionary Should Contain Value ${resp.json()['form']} bulkan
Dictionary Should Contain Value ${resp.json()['form']} evcimen
Head Request
[Tags] head
Create Session httpbin http://httpbin.org
${resp}= Head Request httpbin /headers
Should Be Equal As Strings ${resp.status_code} 200
Options Request
[Tags] options
Create Session httpbin http://httpbin.org
${resp}= Options Request httpbin /headers
Should Be Equal As Strings ${resp.status_code} 200
Dictionary Should Contain Key ${resp.headers} allow
Delete Request With URL Params
[Tags] delete
Create Session httpbin http://httpbin.org
&{params}= Create Dictionary key=value key2=value2
${resp}= Delete Request httpbin /delete ${params}
Should Be Equal As Strings ${resp.status_code} 200
Delete Request With No Data
[Tags] delete
Create Session httpbin http://httpbin.org
${resp}= Delete Request httpbin /delete
Should Be Equal As Strings ${resp.status_code} 200
Delete Request With Data
[Tags] delete
Create Session httpbin http://httpbin.org debug=3
&{data}= Create Dictionary name=bulkan surname=evcimen
${resp}= Delete Request httpbin /delete data=${data}
Should Be Equal As Strings ${resp.status_code} 200
Log ${resp.content}
Comment Dictionary Should Contain Value ${resp.json()['data']} bulkan
Comment Dictionary Should Contain Value ${resp.json()['data']} evcimen
Patch Requests
[Tags] patch
Create Session httpbin http://httpbin.org
&{data}= Create Dictionary name=bulkan surname=evcimen
&{headers}= Create Dictionary Content-Type=application/x-www-form-urlencoded
${resp}= Patch Request httpbin /patch data=${data} headers=${headers}
Dictionary Should Contain Value ${resp.json()['form']} bulkan
Dictionary Should Contain Value ${resp.json()['form']} evcimen
Get Request With Redirection
[Tags] get
Create Session httpbin http://httpbin.org debug=3
${resp}= Get Request httpbin /redirect/1
Should Be Equal As Strings ${resp.status_code} 200
${resp}= Get Request httpbin /redirect/1 allow_redirects=${true}
Should Be Equal As Strings ${resp.status_code} 200
Get Request Without Redirection
[Tags] get
Create Session httpbin http://httpbin.org
${resp}= Get Request httpbin /redirect/1 allow_redirects=${false}
${status}= Convert To String ${resp.status_code}
Should Start With ${status} 30
Options Request With Redirection
[Tags] options
Create Session httpbin http://httpbin.org
${resp}= Options Request httpbin /redirect/1
Should Be Equal As Strings ${resp.status_code} 200
${resp}= Options Request httpbin /redirect/1 allow_redirects=${true}
Should Be Equal As Strings ${resp.status_code} 200
Head Request With Redirection
[Tags] head
Create Session httpbin http://httpbin.org
${resp}= Head Request httpbin /redirect/1 allow_redirects=${true}
Should Be Equal As Strings ${resp.status_code} 200
Head Request Without Redirection
[Tags] head
Create Session httpbin http://httpbin.org
${resp}= Head Request httpbin /redirect/1
${status}= Convert To String ${resp.status_code}
Should Start With ${status} 30
${resp}= Head Request httpbin /redirect/1 allow_redirects=${false}
${status}= Convert To String ${resp.status_code}
Should Start With ${status} 30
Post Request With Redirection
[Tags] post
Create Session jigsaw http://jigsaw.w3.org
${resp}= Post Request jigsaw /HTTP/300/302.html
Should Be Equal As Strings ${resp.status_code} 200
${resp}= Post Request jigsaw /HTTP/300/302.html allow_redirects=${true}
Should Be Equal As Strings ${resp.status_code} 200
Post Request Without Redirection
[Tags] post
Create Session jigsaw http://jigsaw.w3.org debug=3
${resp}= Post Request jigsaw /HTTP/300/302.html allow_redirects=${false}
${status}= Convert To String ${resp.status_code}
Should Start With ${status} 30
Put Request With Redirection
[Tags] put
Create Session jigsaw http://jigsaw.w3.org debug=3
${resp}= Put Request jigsaw /HTTP/300/302.html
Should Be Equal As Strings ${resp.status_code} 200
${resp}= Put Request jigsaw /HTTP/300/302.html allow_redirects=${true}
Should Be Equal As Strings ${resp.status_code} 200
Put Request Without Redirection
[Tags] put
Create Session jigsaw http://jigsaw.w3.org
${resp}= Put Request jigsaw /HTTP/300/302.html allow_redirects=${false}
${status}= Convert To String ${resp.status_code}
Should Start With ${status} 30
Do Not Pretty Print a JSON object
[Tags] json
Comment Define json variable.
&{var}= Create Dictionary key_one=true key_two=this is a test string
${resp}= Get Request httpbin /get params=${var}
Set Suite Variable ${resp}
Should Be Equal As Strings ${resp.status_code} 200
${jsondata}= To Json ${resp.content}
Dictionaries Should Be Equal ${jsondata['args']} ${var}
Pretty Print a JSON object
[Tags] json
Comment Define json variable.
Log ${resp}
${output}= To Json ${resp.content} pretty_print=True
Log ${output}
Should Contain ${output} "key_one": "true"
Should Contain ${output} "key_two": "this is a test string"
Should Not Contain ${output} {u'key_two': u'this is a test string', u'key_one': u'true'}
Set Pretty Print to non-Boolean value
[Tags] json
Comment Define json variable.
Log ${resp}
${output}= To Json ${resp.content} pretty_print="Hello"
Log ${output}
Should Contain ${output} "key_one": "true"
Should Contain ${output} "key_two": "this is a test string"
Should Not Contain ${output} {u'key_two': u'this is a test string', u'key_one': u'true'}
自定义关键字
上面用的都是别人已经写好了的关键字,肯定不能cover所有的场景,一旦已有的keyword不能满足我们的需要了,就得自己写了,这就用到了自定义关键字,具体我还不怎么了解,有兴趣的可以去官网上学一学,感觉还是会很有用的。