背景
断言是接口自动化测试的核心部分,它确保了测试的准确性和可靠性。
在实际落地项目过程中,如果直接使用uniitest自带的断言功能,未优化和封装断言模块,编写的断言脚本如下代码所示:
def testCase_demo1(self):
# 测试步骤
res = requests.post(url=self.url, headers=self.headers, json={})
# 断言
self.assertEqual(200, res.status_code)
self.assertIn('responseTime', res.text, msg='校验失败,响应体responseTime不存在')
self.assertIn('pageBodies', res.text, msg='校验失败,响应体pageBodies不存在')
self.assertIn('body', res.json()["pageBodies"][0], msg='校验失败,响应体body不存在')
self.assertIn('contentVersion', res.json()["pageBodies"][0], msg='校验失败,响应体contentVersion不存在')
self.assertIn('contentUpdateTime', res.json()["pageBodies"][0], msg='校验失败,响应体contentUpdateTime不存在')
self.assertIn('valid', res.json()["pageBodies"][0], msg='校验失败,响应体valid不存在')
self.assertTrue(type(res.json()['pageBodies'] == list))
self.assertTrue(type(res.json()['responseTime'] == int))
for pagebody in res.json()["pageBodies"]:
if pagebody["pageId"] == pageId:
self.assertEqual(pageId, pagebody["pageId"])
self.assertEqual('abc', pagebody["body"])
self.assertEqual('a', pagebody["title"])
self.assertEqual('a', pagebody["summary"])
self.assertEqual(0, pagebody["bodyType"])
未封装断言模块之前带来的痛点问题:
1)断言步骤繁琐,影响团队成员编码效率;
2)断言规范未明确,团队内各成员对断言的严谨程度把控不一致。
为了解决这些痛点问题,作为框架开发者,在团队内部定义好断言规范后,可以对断言模块进行封装,达到匹配项目断言要求、提高测试代码的编写效率的目的。
下面阐述具体落地实现思路。
实现思路
首先罗列下接口自动化响应体需要校验的内容:
①接口响应状态码、
②接口文档返回体key值是否存在、
③接口返回体不存在多余key值、
④value精确值校验、
⑤value动态值的类型校验。
具体实现思路:
通过字段的长度对齐和字段是否存在于实际结果校验是否存在多余字段和对齐协议文档中的字段
定义方法的使用协议,支持动态值的校验和精准值的校验,如果是动态值只需要描述值的类型即可校验key的type,如果是精准值会同时校验类型和值
通过类型判断找出嵌套结构,并使用递归函数实现嵌套结构的精准校验
通过类型判断找出列表结构实现列表元素值的校验
实现代码
验证可用性
断言示范1:字段值(“responseTime”)类型不一致,断言失败
def testCase_demo1(self):
actual = {
"responseTime": "27",
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": 1652083950000,
"infoVersion": 1,
"infoUpdateTime": 1652083950000,
"title": "a",
"summary": "a"
}
]
}
expect = {
"responseTime": int,
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": int,
"infoVersion": 1,
"infoUpdateTime": int,
"title": "a",
"summary": "a"
}
]
}
self.output_check(expect, actual)
断言示范2:精确值(“responseTime”)不一致,断言失败
def testCase_demo1(self):
actual = {
"responseTime": 27,
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": 1652083950000,
"infoVersion": 2,
"infoUpdateTime": 1652083950000,
"title": "a",
"summary": "a"
}
]
}
expect = {
"responseTime": 2,
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": int,
"infoVersion": 1,
"infoUpdateTime": int,
"title": "a",
"summary": "a"
}
]
}
self.output_check(expect, actual)
断言示范3:嵌套结构内精确值(info列表首个字典下的id值)不一致,断言失败
def testCase_demo1(self):
actual = {
"responseTime": 27,
"info": [
{
"id": "AAAf24d873f345387fb33693e64a0e26d76",
"createTime": 1652083950000,
"infoVersion": 2,
"infoUpdateTime": 1652083950000,
"title": "a",
"summary": "a"
}
]
}
expect = {
"responseTime": int,
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": int,
"infoVersion": 1,
"infoUpdateTime": int,
"title": "a",
"summary": "a"
}
]
}
self.output_check(expect, actual)
断言示范4:嵌套结构内元素(info列表下首个字典)长度不一致,断言失败
def testCase_demo1(self):
actual = {
"responseTime": 27,
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": 1652083950000,
"infoVersion": 2,
"infoUpdateTime": 1652083950000,
"title": "a",
"summary": "a"
}
]
}
expect = {
"responseTime": int,
"info": [
{
"id": "f24d873f345387fb33693e64a0e26d76",
"createTime": int,
"infoVersion": 1,
"infoUpdateTime": int,
"title": "a",
# "summary": "a"
}
]
}
self.output_check(expect, actual)
这样,我们就完成了自定义断言的封装逻辑。通过封装,可以规范断言严谨度,提高测试脚本的可读性和可维护性,并使断言操作更加灵活和符合需求。同时,自定义断言方法也可以帮助我们快速定位测试用例失败的原因,提高排查问题的效率。