HTTP 接口测试很简单,不管工具、框架、还是平台,只要很的好的几个点就是好工具。
- 测试数据问题:比如删除接口,重复执行还能保持结果一致,必定要做数据初始化。
- 接口依赖问题:B 接口依赖 A 的返回值,C 接口依赖 B 接口的返回值。
- 加密问题:不同的接口加密规则不一样。有些用到时间戳、md5、base64、AES,如何提供种能力。
- 断言问题:有些接口返回的结构体很复杂,如何灵活的做到断言。
对于以上问题,工具和平台要么不支持,要么很麻烦,然而框架是最灵活的。
unittest/pytest + requests/https 直接上手写代码就好了,既简单又灵活。
那么同样是写代码,A 框架需要 10 行,B 框架只需要 5 行,然而又不失灵活性,那我当然是选择更少的了,毕竟,人生苦短嘛。
seldom 适合个人接口自动化项目,它有以下优势。
- 可以写更少的代码
- 自动生成 HTML/XML 测试报告
- 支持参数化,减少重复的代码
- 支持生成随机数据
- 支持 har 文件转 case
- 支持数据库操作
这些是 seldom 支持的功能,我们只需要集成 HTTP 接口库,并提供强大的断言即可。seldom 2.0
加入了 HTTP 接口自动化测试支持。
Seldom 兼容 Requests API 如下:
Seldom VS Request+unittest
先来看看 unittest + requests 是如何来做接口自动化的:
-
import unittest
-
import requests
-
class TestAPI(unittest.TestCase):
-
def test_get_method(self):
-
payload = {'key1': 'value1', 'key2': 'value2'}
-
r = requests.get("http://httpbin.org/get", params=payload)
-
self.assertEqual(r.status_code, 200)
-
if __name__ == '__main__':
-
unittest.main()
这其实已经非常简洁了。同样的用例,用 seldom 实现。
-
# test_req.py
-
import seldom
-
class TestAPI(seldom.TestCase):
-
def test_get_method(self):
-
payload = {'key1': 'value1', 'key2': 'value2'}
-
self.get("http://httpbin.org/get", params=payload)
-
self.assertStatusCode(200)
-
if __name__ == '__main__':
-
seldom.main()
主要简化点在,接口的返回数据的处理。当然,seldom 真正的优势在断言、日志和报告。
har to case
对于不熟悉 Requests 库的人来说,通过 Seldom 来写接口测试用例还是会有一点难度。于是,seldom 提供了har
文件转 case
的命令。
首先,打开 fiddler 工具进行抓包,选中某一个请求。
然后,选择菜单栏:file
-> Export Sessions
-> Selected Sessions...
选择导出的文件格式。
点击next
保存为demo.har
文件。
最后,通过seldom -h2c
转为demo.py
脚本文件。
-
> seldom -h2c .\demo.har
-
.\demo.py
-
2021-06-14 18:05:50 [INFO] Start to generate testcase.
-
2021-06-14 18:05:50 [INFO] created file: D:\.\demo.py
demo.py
文件。
-
import seldom
-
class TestRequest(seldom.TestCase):
-
def start(self):
-
self.url = "http://httpbin.org/post"
-
def test_case(self):
-
headers = {"User-Agent": "python-requests/2.25.0", "Accept-Encoding": "gzip, deflate", "Accept": "application/json", "Connection": "keep-alive", "Host": "httpbin.org", "Content-Length": "36", "Origin": "http://httpbin.org", "Content-Type": "application/json", "Cookie": "lang=zh"}
-
cookies = {"lang": "zh"}
-
self.post(self.url, json={"key1": "value1", "key2": "value2"}, headers=headers, cookies=cookies)
-
self.assertStatusCode(200)
-
if __name__ == '__main__':
-
seldom.main()
运行测试
打开 debug 模式seldom.run(debug=True)
运行上面的用例。
-
> python .\test_req.py
-
2021-04-29 18:19:39 [INFO] A run the test in debug mode without generating HTML report!
-
2021-04-29 18:19:39 [INFO]
-
__ __
-
________ / /___/ /___ ____ ____
-
/ ___/ _ \/ / __ / __ \/ __ ` ___/
-
(__ ) __/ / /_/ / /_/ / / / / / /
-
/____/\___/_/\__,_/\____/_/ /_/ /_/
-
-----------------------------------------
-
@itest.info
-
test_get_method (test_req.TestAPI) ...
-
----------- Request ---------------
-
url: http://httpbin.org/get method: GET
-
----------- Response ️ -------------
-
type: json
-
{'args': {'key1': 'value1', 'key2': 'value2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-608a883c-7b355ba81fcd0d287566405a'}, 'origin': '183.178.27.36', 'url': 'http://httpbin.org/get?key1=value1&key2=value2'}
-
ok
-
----------------------------------------------------------------------
-
Ran 1 test in 0.619s
-
OK
通过日志/报告都可以清楚的看到。
- 请求的方法
- 请求 url
- 响应的类型
- 响应的数据
更强大的断言
断言接口返回的数据是我们在做接口自动化很重要的工作。
assertJSON
接口返回结果如下:
-
{
-
"args": {
-
"hobby": [
-
"basketball",
-
"swim"
-
],
-
"name": "tom"
-
}
-
}
我的目标是断言name
和 hobby
部分的内容。seldom 可以针对JSON
文件进行断言。
-
import seldom
-
class TestAPI(seldom.TestCase):
-
def test_assert_json(self):
-
payload = {'name': 'tom', 'hobby': ['basketball', 'swim']}
-
self.get("http://httpbin.org/get", params=payload)
-
assert_json = {'args': {'hobby': ['swim', 'basketball'], 'name': 'tom'}}
-
self.assertJSON(assert_json)
运行日志
-
test_get_method (test_req.TestAPI) ...
-
----------- Request ---------------
-
url: http://httpbin.org/get method: GET
-
----------- Response ️ -------------
-
type: json
-
{'args': {'hobby': ['basketball', 'swim'], 'name': 'tom'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-608a896d-48fac4f6139912ba01d2626f'}, 'origin': '183.178.27.36', 'url': 'http://httpbin.org/get?name=tom&hobby=basketball&hobby=swim'}
-
Assert data has not key: headers
-
Assert data has not key: origin
-
Assert data has not key: url
-
ok
-
----------------------------------------------------------------------
-
Ran 1 test in 1.305s
-
OK
seldom 还会提示你还有哪些字段没有断言。
assertPath
接口返回数据如下:
-
{
-
"args": {
-
"hobby":
-
["basketball", "swim"],
-
"name": "tom"
-
}
-
}
seldom 中可以通过 path 进行断言:
-
import seldom
-
class TestAPI(seldom.TestCase):
-
def test_assert_path(self):
-
payload = {'name': 'tom', 'hobby': ['basketball', 'swim']}
-
self.get("http://httpbin.org/get", params=payload)
-
self.assertPath("name", "tom")
-
self.assertPath("args.hobby[0]", "basketball")
assertSchema
有时并不关心数据本身是什么,而是需要断言数据的类型。 assertSchema
是基于 jsonschema
实现的断言方法。
jsonschema: https://json-schema.org/learn/
接口返回数据如下:
-
{
-
"args": {
-
"hobby":
-
["basketball", "swim"],
-
"name": "tom",
-
"age": "18"
-
}
-
}
seldom 中可以通过利用jsonschema
进行断言:
-
import seldom
-
class TestAPI(seldom.TestCase):
-
def test_assert_schema(self):
-
payload = {"hobby": ["basketball", "swim"], "name": "tom", "age": "18"}
-
self.get("/get", params=payload)
-
schema = {
-
"type": "object",
-
"properties": {
-
"args": {
-
"type": "object",
-
"properties": {
-
"age": {"type": "string"},
-
"name": {"type": "string"},
-
"hobby": {
-
"type": "array",
-
"items": {
-
"type": "string"
-
},
-
}
-
}
-
}
-
},
-
}
-
self.assertSchema(schema)
是否再次感受到了 seldom 提供的断言非常灵活,强大。
接口数据依赖
在场景测试中,我们需要利用上一个接口的数据,调用下一个接口。
-
import seldom
-
class TestRespData(seldom.TestCase):
-
def test_data_dependency(self):
-
"""
-
Test for interface data dependencies
-
"""
-
headers = {"X-Account-Fullname": "bugmaster"}
-
self.get("/get", headers=headers)
-
self.assertStatusCode(200)
-
username = self.response["headers"]["X-Account-Fullname"]
-
self.post("/post", data={'username': username})
-
self.assertStatusCode(200)
seldom 提供了self.response
用于记录上个接口返回的结果,直接拿来用即可。
数据驱动
seldom 本来就提供的有强大的数据驱动,拿来做接口测试非常方便。
@data
-
import seldom
-
from seldom import data
-
class TestDDT(seldom.TestCase):
-
@data([
-
("key1", 'value1'),
-
("key2", 'value2'),
-
("key3", 'value3')
-
])
-
def test_data(self, key, value):
-
"""
-
Data-Driver Tests
-
"""
-
payload = {key: value}
-
self.post("/post", data=payload)
-
self.assertStatusCode(200)
-
self.assertEqual(self.response["form"][key], value)
@file_data
创建data.json
数据文件
-
{
-
"login": [
-
["admin", "admin123"],
-
["guest", "guest123"]
-
]
-
}
通过file_data
实现数据驱动。
-
import seldom
-
from seldom import file_data
-
class TestDDT(seldom.TestCase):
-
@file_data("data.json", key="login")
-
def test_data(self, username, password):
-
"""
-
Data-Driver Tests
-
"""
-
payload = {username: password}
-
self.post("http://httpbin.org/post", data=payload)
-
self.assertStatusCode(200)
-
self.assertEqual(self.response["form"][username], password)
更过数据文件 (csv/excel/yaml),参考
随机生成测试数据
seldom 提供随机生成测试数据方法,可以生成一些常用的数据。
-
import seldom
-
from seldom import testdata
-
class TestAPI(seldom.TestCase):
-
def test_data(self):
-
phone = testdata.get_phone()
-
payload = {'phone': phone}
-
self.get("http://httpbin.org/get", params=payload)
-
self.assertPath("args.phone", phone)
更过类型的测试数据,参考
数据库操作
seldom 支持 sqlite3、MySQL 数据库操作。
连接数据库
连接 sqlit3 数据库
-
from seldom.db_operation import SQLiteDB
-
db = SQLiteDB(r"D:\learnAPI\db.sqlite3")
连接 MySQL 数据库(需要)
- 安装 pymysql 驱动
> pip install pymysql
- 链接
-
from seldom.db_operation import MySQLDB
-
db = MySQLDB(host="127.0.0.1",
-
port="3306",
-
user="root",
-
password="123",
-
database="db_name")
操作方法
- delete_data
删除表数据。
db.delete_data(table="user", where={"id":1})
- insert_data
插入一条数据。
-
data = {'id': 1, 'username': 'admin', 'password': "123"},
-
db.insert_data(table="user", data=data)
- select_data
查询表数据。
-
result = db.select_data(table="user", where={"id":1, "name": "tom"})
-
print(result)
- update_data
更新表数据。
db.update_data(table="user", data={"name":"new tom"}, where={"name": "tom"})
- init_table
批量插入数据,在插入之前先清空表数据。
-
datas = {
-
'api_event': [
-
{'id': 1, 'name': '红米Pro发布会'},
-
{'id': 2, 'name': '可参加人数为0'},
-
{'id': 3, 'name': '当前状态为0关闭'},
-
{'id': 4, 'name': '发布会已结束'},
-
{'id': 5, 'name': '小米5发布会'},
-
],
-
'api_guest': [
-
{'id': 1, 'real_name': 'alen'},
-
{'id': 2, 'real_name': 'has sign'},
-
{'id': 3, 'real_name': 'tom'},
-
]
-
}
-
db.init_table(datas)
- close
关闭数据库连接。
db.close()
总结:
感谢每一个认真阅读我文章的人!!!
作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。
软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。