封装assert 与 jsonpath

该博客介绍了如何进行接口响应的断言检查,包括使用JSONPath提取响应数据,以及如何对比预期结果。同时,文章提到了Faker库在生成测试数据时的应用,提供多种语言和数据类型的生成选项。

断言

  1. 从响应结果当中,提取表达式
  2. 期望结果
  3. 比对方式 = 相等…
{"expr":"$.code",  # "expr"指的是实际结果 :"$.code" 指的是 通过 jsonpath 元素定位获取的值 名称
"expected":0,	   # "expected" 指的是希望结果: 0 指的是 得到的结果
"type":"eq"}	   # "type" 指的是 希望结果: "eq"指的是实际结果,两则比对是否相等,如同:希望结果 == 实际结果

1、必须是列表形式
2、列表中的成员,必须是字典形式
3、字典必须有3个key:expr, expected, type
4、type表示实际和期望如何去比对,有以下值可以使用:eq,gt,in

[{"expr":"$.code","expected":0,"type":"eq"}, \
{"expr":"$.msg","expected":"OK","type":"eq"}, \
{"expr":"$..mobile_phone""expected":"18610100022""type":"eq"}]

========================================================

jsonpath

这是JSONPath语法元素与其XPath对应元素的完整概述和并排比较。
也可参照官网地址:https://goessner.net/articles/JsonPath/index.html#e2
如何提取,请参照如下:

XPathJSONPath描述
/$根对象/元素
.@当前的对象/元素
/. 或者 [ ]后代(直属后代:子辈)
. .不适用父运算符
//. .递归下降。JSONPath从E4X借用此语法。(用的情况较多,在自己的后代中:子辈、孙辈)
**通配符。所有对象/元素,无论其名称如何。
@不适用属性访问。JSON结构没有属性。
[ ][ ]下标运算符。XPath使用它来遍历元素集合和谓词。在Javascript和JSON中,它是本机数组运算符。
在这里插入图片描述[ , ]XPath中的Union运算符导致节点集的组合。JSONPath允许将备用名称或数组索引作为一组。
不适用[开始:结束:步骤]从ES4借用的数组分片运算符。
[ ]?()应用过滤器(脚本)表达式。
不适用()脚本表达式,使用基础脚本引擎。
()不适用在Xpath中分组

=================================================================

期望结果 与 实际结果比对

下列使用代码编写:

import ast
import jsonpath

# 从excel当中,读取出来的断言列表
check_srt = '[{"expr":"$.code","expected":0,"type":"eql"}, ' \
            '{"expr":"$.msg","expected":"OK","type":"eql"},]'

# 把字符串转换成python列表
check_list = ast.literal_eval(check_srt)    # 使用 ast.literal_eval 记得先导入 import ast
print(check_list)	
""" 打印得到的结果:
[{'expr': '$.code', 'expected': 0, 'type': 'eql'}, {'expr': '$.msg', 'expected': 'OK', 'type': 'eql'}]
"""
#	=================================================================
"""
1、从响应结果当中,提取表达式 -- jsonpath
jsonpath在线使用:http://jsonpath.com/    

2、如何从响应果当中,通过jsonpath表达式,提取出要比对的数据。
		第三方库:jsonpath	使用jsonpath, 记得先导入:import jsonpath
		安装:pip install jsonpath
用法:jsonpath.jsonpath(response.json(), jsonpath表达式)
返回:列表。如果没有匹配到,返回False
"""

# 响应结果
response = {
    "code": 0,
    "msg": "OK",
    "data": {
        "id": 1000398923,
        "reg_name": "白糖",
        "mobile_phone": "13567748360"
    }
}

check_res = []		# 定义一个比对结果的列表,有多个比对时使用列表,可以更明确

for check in check_list:	# 遍历check_list列表
    # actual = 通过jsonpath表达式,从响应结果当中拿到了实际结果
    actual = jsonpath.jsonpath(response, check_index["expr"])[0]
    if isinstance(actual,list):		# 判断:如果 actual 的类型是个 列表:actual = actual[0]
        actual = actual[0]
    
    # 与实际结果做比对    
    if check_index["type"] == "eql":
    	check_res.append(actual == check_index["expected"])
print(check_res)	# 打印比对的结果是:[True, True];	成功是:True	失败是:False

    if False in check_res:
    	print("断言失败!请查看结果为:False")
  		raise AssertionError
	else:
  		print("所有断言成功!")

=================================================================

封装 期望结果 与 实际结果比对

import ast
import jsonpath

class MyAssert:
    def assert_response_value(self, check_str, response_dict):
        """
        
        :param check_str: 从excel当中,读取出来的断言列。是一个列表形式的字符串。里面的成员是一个断言
        :param response_dict: 接口请求之后的响应数据,是字典类型。
        :return: None
        """
        # 所有断言的比对结果列表
        check_res = []
        
        # 把字符串转换成python列表
        check_list = ast.literal_eval(check_str)
        print(check_list)

        for check_index in check_list:
            actual = jsonpath.jsonpath(response_dict, check_index["expr"])[0]
            if isinstance(actual, list):
                actual = actual[0]

            # 与实际结果做比对
            if check_index["type"] == "eql":
                check_res.append(actual == check_index["expected"])

        if False in check_res:
            raise AssertionError
            

=================================================================

faker

faker造数据:
faker的官方文档:https://faker.readthedocs.io/en/master/locales.html
测试派文章:http://testingpai.com/article/1615615023407>

1、安装:
pip install faker

2、使用:
   1) 导入:from faker import Faker
   2) 语言支持:
        简体中文:zh_CN
        繁体中文:zh_TW
        美国英文:en_US
        英国英文:en_GB
        德文:de_DE
        日文:ja_JP
        韩文:ko_KR
        法文:fr_FR
        比如中文:f = Faker("zh_CN")

   3) faker提供的数据生成类型:
       faker.Provider

示例:
f = Faker("zh_CN")
print(f.phone_number())

from _ast import operator from typing import Callable, Any import jsonpath from unit_tools.exceptions import AssertTypeError class Assertions: """ 接口断言模式封装 1) 状态码断言 2) 包含模式断言 3) 相等断言 4) 不相等断言 """ @classmethod def status_code_assert(cls, expected_result, status_code): """ 接口的响应状态码断言 :param expected_result: (int)yaml文件code模式中的预期状态码 :param status_code: (int)接口实际返回的状态码 :return: """ # 断言状态标识,0 表示成功,其他表示失败 failure_count = 0 if not isinstance(expected_result, int): expected_result = int(expected_result) if expected_result == status_code: print(f'状态吗断言成功:接口实际返回状态码{status_code} == {expected_result}') else: print(f'断言失败:接口实际返回状态码{status_code} != {expected_result}') failure_count += 1 return failure_count @classmethod def contain_assert(cls, expected_result, response): """ 字符串包含模式,断言预期结果字符串是否包含在接口的实际响应返回信息中 :param expected_result: (dict)yaml文件里面contain模式的数据 :param response: (dict)接口的实际响应信息 :return: """ # 断言状态标识,0 表示成功,其他表示失败 failure_count = 0 for assert_key, assert_value in expected_result.items(): response_list = jsonpath.jsonpath(response, f'$..{assert_key}') if response_list and isinstance(response_list[0], str): response_str = ''.join(response_list) success_message = f"包含模式断言成功:预期结果【{assert_value}】存在于实际结果【{response_str}】中" failure_message = f"包含模式断言失败:预期结果【{assert_value}】未在实际结果【{response_str}】中找到" if assert_value in response_str: print(success_message) else: failure_count = failure_count + 1 print(failure_message) return failure_count @classmethod def equal_assert(cls, expected_result, response): """ 相等断言,根据yaml里面的validation关键词下面的ne模式数据去跟接口实际响应信息对比 :param expected_result: (dict)yaml里面的eq值 :param response: (dict)接口实际响应结果 :return: """ failure_count = 0 if isinstance(response, dict) and isinstance(expected_result, dict): # 找出实际结果预期结果共同的key值 common_key = list(expected_result.keys() & response.keys()) if common_key: # 找出实际结果预期结果共同的key值 common_key = common_key[0] new_actual_result = {common_key: response[common_key]} eq_assert = operator.__eq__(new_actual_result, expected_result) if eq_assert: print(f"相等断言成功:接口实际结果{new_actual_result} == 预期结果:{expected_result}") else: failure_count += 1 print(f"相等断言失败:接口实际结果{new_actual_result} != 预期结果:{expected_result}") else: failure_count += 1 print('相等断言失败,请检查yaml文件eq模式的预期结果或接口返回值是否正确') return failure_count @classmethod def assert_result(cls, expected_result, response, status_code): """ 断言主函数,通过all_flag标记,如all_flag == 0表示测试成功,否则为失败 :param expected_result: (list)yaml文件validation关键词下面的预期结果 :param response: (dict)接口的实际响应信息 :param status_code: (int)接口的实际响应状态码 :return: """ all_flag = 0 # 通过字典映射方式管理不同的断言方式 assert_methods = { 'code': cls.status_code_assert, 'contain': cls.contain_assert, 'eq': cls.equal_assert # 'ne': cls.not_equal_assert, } try: for yq in expected_result: for assert_mode, assert_value in yq.items(): # 表示assert_method是一个接受两个参数,类型为Any表示可以是任意类型,并返回整数的可调用对象 assert_method: Callable[[Any, Any], int] = assert_methods.get(assert_mode) if assert_method: # 调用对应的断言方法,传递适当的参数 if assert_mode in ['code']: flag = assert_method(assert_value, status_code) else: flag = assert_method(assert_value, response) all_flag += flag else: raise AssertTypeError(f'不支持{assert_mode}该断言模式') except Exception as exceptions: raise exceptions assert all_flag == 0, '测试失败' print('测试成功')
08-06
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值