Api 自动化测试
个人源码:https://github.com/wupeng-paynewinn/ApiTest_Unittest
整体:
- ApiTest
- Common
- A.py
- BaseTest.py
- Cache.py
- Decorator.py
- General.py
- Third.py
- init.py
- Config
- config.ini
- product-config.ini
- test-config.ini
- Report
- init.py
- TestReport.html
- TestCase
- test_01_02_login.py
- …
- TestDate
- 01_02_login.json
- …
- readme.md
- requirements.txt
- run_all_case.py
- Common
一、Config 模块
|-- config.ini
|-- product-config.ini
|-- test-config.ini
在 config.ini 中的 [ENVIRONMENT]
块中定义环境、发件人、收件人、邮件主题,如:
[ENVIRONMENT]
environment=test
[SENDER]
smtpserver = mail.qq.com
user = xxx@qq.com
password = xxxxxx
sender = xxx@qq.com
[RECEIVER]
;receiver = xx1@xx.com, xx2@xx.com
receiver = xx@xx.com
[MSG]
subject = 小象自动定时测试报告(生产api)
将会读取 test-config.ini 文件中的配置,由这种方式将配置文件与环境剥离开。
[HOST]
cn_https=https://xxx.10jqka.com.cn
cn_http=http://xxx.10jqka.com.cn
en_https=https://
en_http=http://
在 [HOST]
块中定义host,可以在 case.json 文件中使用,如:
{
"request": {
"host": "{{cn_https}}",
"api": "/info/api/v3/auth/post/login",
"method": "POST",
"header": {
"Content-Type": "application/x-www-form-urlencoded"
}
},
....
}
使用 {{}}
包裹,将会从config中解析。否则,当成字符串处理
二、case 定义形式
测试用例,以 json 文件的形式定义。主要包括一个 request 块,和多个 case 块。基本的形式如下:
{
"request": {
"host": "{{cn_https}}",
"api": "/info/api/v3/auth/post/login",
"method": "POST",
"header": {
"Content-Type": "application/x-www-form-urlencoded"
}
},
"case_01": {
"query":"test=1&test2=2",
"data": [
{
"key": "useragent",
"value": "android",
"type": "text"
}
],
"assert": [
{
"type": "eq",
"rules": "status",
"expect": 0,
"msg": "这里是报错显示的msg"
}
],
"set_result": [
{
"key": "cache_key",
"value": "payload.id"
}
]
}
}
request
对象中包含:
- host:在config 中定义
- api:接口地址,与host组成完整url
- method:请求方式,支持POST与GET
- header:对象,可填写多个键值对
case_01
为用例名称,一个json文件中可以含有多个用例。同一个文件下所有的用例,请求的内容都相同。
-
query: 字符串,按照"field1=value1&field2=value2"规则,解析结果将于data合并
-
data: 数组,按照method内容,post则放在body中发送,get则放在url中。数组中可放入多个对象。
- key: 必填,参数名称。
- value:必填,请求内容。
- type:必填,类型:text/array/json/file
- file_name: 非必填,type 为 file 时需要参数。文件名称。
- file_type: 非必填,type 为 file 时需要参数。文件类型。例子:text/plain
- from:非必填,数据来源。当数据来源于cache时,填cache。目前只支持cache
-
assert:数组,定义请求结果断言。可以含有多个对象,定义不同的断言,
- type:断言类型,eq/not_eq等
- rules:取值规则,返回数据中的结构 例如 payload.group_id
- expect: 预期值,对比用
-
set_result:非必填 数组,需要保存在cache中的数据
- key: 名称,注意唯一性
- result_field:返回数据的结构 例如:payload.group_id
三、定义单元测试
# -*- coding: utf-8 -*-
import unittest
from Common.BaseTest import BaseTest
# 定义测试类
class TestLogin(BaseTest):
# 定义测试用例文件地址
json_file = "/TestData"
# 定义单个测试用例
def test_01_login(self):
# 定义需要执行的case名称
self.run_case("case_01")
def test_02_login(self):
self.run_case("case_02")
# 保存全部返回结果
self.set_result("286592399")
def test_03_create_group(self):
# 在用例中定义测试用例文件地址
self.set_json_file("/TestData")
# 定义单个参数
self.set_single_extra_body("code_list", "1112,1113")
self.set_single_extra_body("code", "1200")
self.run_case("case_01")
if __name__ == '__main__':
unittest.main()
四、Cache 模块
为了方便用例间上下文联动,引入cache模块。可以将接口返回的结果保存在cache中,也可以从cache中取出所需要的内容放入到请求体中。
但需要注意的是,cache模块受用例执行顺序的影响,必须保证当前取值的用例在存值用例的后面执行。
使用:
-
配合 json 文件:
-
存值,在 {case_name}.set_result 块中定义需要保存的数据
例如:
{ "set_result": [ { "key": "286592399_token", "result_field": "payload.token" }, { "key": "286592399_all", "result_field": "*" } ] }
-
取值,在 {case_name}.data 块中定义需要取值的数据
例如:
{ "data": [ { "key": "token", "value": "{{286592399_token}}", "type": "text" } ] }
data 中使用
{{}}
将会从cache中取值 -
-
配合 test 类:
-
存值:
使用 set_result 方法保存全部数据。
self.run_case("case_02") self.set_result("286592399")
这两个方法会将
case_02
的所有返回结果保存在286592399
键中。set_result 方法 必须在 run_case 之后执行。也可以写成:
self.run_case("case_02").set_result("286592399")
-
取值:
使用 get_result 方法从cache中取值。
self.get_cache(key="286592399",r="")
其中,r 为取值规则。如果为空,则将
286592399
键中所有数据取出,如果需要取出指定结构下的数据,只需要给r
设定规则,例如:self.get_cache(key="286592399",r="payload.token")
-
五、给case请求体增加参数
-
增加 header
-
set_extra_header
self.set_extra_header({"test_header":"header","test_data2":"header"})
-
set_single_extra_header
self.set_single_extra_header(key="test_header",value="header")
-
-
增加 body(post):
将在body体中传输
-
set_extra_body
self.set_extra_body({"test_data":"data","test_data1":"data"})
-
set_single_extra_body
self.set_single_body(key="test_data",value="1")
-
-
增加 params (get):
将在url中传输
-
set_extra_params
self.set_extra_body({"test_data":"data","test_data1":"data"})
-
set_single_extra_params
self.set_single_body(key="test_data",value="1")
以上将被解析为: http://www.domian.com/some_api?test_data=data&test_data1=data
-
六、执行顺序问题
在 run_all_case.py
文件中定义测试用例执行:
suite = unittest.TestSuite()
suite.addTest(TestVanishLogin('test_1_login_01'))
suite.addTest(TestVanishLogin('test_1_login_02'))
suite.addTest(TestVanishLogin('test_2_create_01'))
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
使用 addTest 手动增加测试用例,设置执行顺序。在执行用例很多的情况下,比较麻烦,也可以使用:
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
#runner.run(discover)
runner = HTMLTestRunner(stream=fp, title=u'测试报告', description=u'用例执行情况:')
runner.run(discover)
使用自动 discover 功能,自动加载所有测试用例,但其加载执行的顺序是按照文件名和方法名排序的。
需要优先执行的文件可以将文件名命名为: test_1_1_1_vanish_account_login.py
文件内需要优先执行的用例可以将方法名命名为: test_1_1_account_login_01()
用名称中的数字用来控制用例执行顺序。