自动化测试框架Pytest(八)——断言

断言是一种除错机制,用于验证代码是否符合编码人员的预期。

pytest自带的assert断言有以下几种语法:

import time
测试类名必须以Test开头,并且不能有init方法
class Test1:
    # • assert xx :判断xx为真
    # • assert not xx :判断xx不为真
    # • assert a in b :判断b包含a
    # • assert a == b :判断a 等于b
    # • assert a != b :判断a不等于b
    #测试方法必须以test开头
    def test_01(self):
        print('------------方法test_01------------')
        assert "a" in "abc"
    def test_02(self):
        print('------------方法test_02------------')
        assert 3+2 == 5

正确会自动跳过

自动化测试框架Pytest(八)——断言

错误会有以下提示

自动化测试框架Pytest(八)——断言

这样我们可以忽略正确的用例,只关注错误的用例,提高每次自动化的整体效率。

为了适配不同的场景,我这边写了一个方法,包含相同匹配和包含匹配:

qw_result为一个数组,数组里一个对象为一个期望结果。对象的key只能写contains或者equals,value写期望的内容。​​​​​​​

import time
测试类名必须以Test开头,并且不能有init方法
import jsonpath
class Test1:
    # • assert xx :判断xx为真
    # • assert not xx :判断xx不为真
    # • assert a in b :判断b包含a
    # • assert a == b :判断a 等于b
    # • assert a != b :判断a不等于b
    #测试方法必须以test开头
    def test_01(self):
        print('------------方法test_01------------')
        qw_result = [
            {"contains":"you are right"},
            {"equals": {"time": 20201011} },
            {"equals": {"status_code": 200} }
        ]
        sj_result = {"result_task":"you are right", "time":20201011}
        si_return_code = 200
        self.assert_result( qw_result, sj_result, si_return_code)
    def test_02(self):
        print('------------方法test_02------------')
    # 断言
    def assert_result(self, qw_result, sj_result, return_code):
        all_flag = 0
        for yq in qw_result:
            for key, value in yq.items():
                # print(key,value)
                if key == "equals":
                    flag = self.equals_assert(value, sj_result, return_code)
                    all_flag = all_flag + flag
                elif key == "contains":
                    flag = self.contains_assert(value, sj_result)
                    all_flag = all_flag + flag
                else:
                    print("框架暂不支持这种断言方式")
        assert all_flag == 0
    # 相等断言
    def equals_assert(self, value, sj_result, return_code):
        flag = 0
        for assert_key, assert_value in value.items():
            # print(assert_key,assert_value)
            if assert_key == "status_code":
                if assert_value != return_code:
                    flag = flag + 1
                    print("断言失败,返回的状态码不等于%s" % return_code)
            else:
                # list为实际json匹配出来的值
                lists = jsonpath.jsonpath(sj_result, '$..%s' % assert_key)
                if lists:
                    if assert_value not in lists:
                        flag = flag + 1
                        print(f"断言失败:{assert_key}不等于{assert_value}")
                else:
                    flag = flag + 1
                    print(f"断言失败:返回的结果不存在{assert_key}")
        return flag
    # 包含断言
    def contains_assert(self, value, sj_result):
        flag = 0
        if value not in str(sj_result):
            flag = flag + 1
            print(f"断言失败,返回结果中不包含{value}")
        return flag

如果不匹配,输出结果会有提示:

自动化测试框架Pytest(八)——断言

最后将该方法写到之前的request_util里:

import json
import re
import requests
import jsonpath
from test7.commons.debug_util import DebugTalk
from test7.commons.yaml_util import write_extract_yaml
class RequestUtil:
    session = requests.session()
    # 替换值的方法
    def replace_value(self, data):
        # 1保存数据类型
        data_type = type(data)
        # 2判断数据类型
        if isinstance(data, dict) or isinstance(data, list):
            str_data = json.dumps(data)
        else:
            str_data = str(data)
        # 替换
        for cs in range(1, str_data.count('${') + 1):
            if "${" in str_data and "}" in str_data:
                start_index = str_data.index("${")
                end_index = str_data.index("}", start_index)
                old_value = str_data[start_index:end_index + 1]
                # print(f"old_value:{old_value}")
                # 反射:通过类的对象和方法字符串去调用方法
                function_name = old_value[2:old_value.index('(')]
                args_value1 = old_value[old_value.index('(') + 1:old_value.index(')')]
                if args_value1 != "":
                    args_value2 = args_value1.split(',')
                    # print(function_name, args_value2)
                    new_value = getattr(DebugTalk(), function_name)(*args_value2)
                else:
                    new_value = getattr(DebugTalk(), function_name)()
                # print(f"new_value:{new_value}")
                # 判断替换的新参数的类型
                if isinstance(new_value, int) or isinstance(new_value, float):
                    str_data = str_data.replace('"' + old_value + '"', str(new_value))
                else:
                    str_data = str_data.replace(old_value, str(new_value))
        # 3还原数据类型
        if isinstance(data, dict) or isinstance(data, list):
            data = json.loads(str_data)
        else:
            data = data_type(str_data)
        return data
    #规范YAML测试用例
    def standard_yaml(self,caseinfo):
        caseinfo_keys = caseinfo.keys()
        # 判断关键词是否完整
        if "name" in caseinfo_keys and "request" in caseinfo_keys and "validate" in caseinfo_keys:
            cs_request = caseinfo['request']
            cs_request_keys = cs_request.keys()
            if "method" in cs_request_keys and "url" in cs_request_keys:
                method = cs_request.pop("method") #pop-删除列表里最后一个并且返回这个值
                url = cs_request.pop("url")
                res = self.send_request(method,url,**cs_request)
                print(res.text)
                # 写入yaml文件
                return_json = ""
                return_code = res.status_code
                try:
                    return_json = res.json()
                except Exception as e:
                    print("返回的结果不是json格式,不能使用jsonpath提取")
                # 提取值并写入extract.yaml文件
                if "extract" in caseinfo_keys:
                    for key, value in caseinfo["extract"].items():
                        if "(.*?)" in value or "(.+?)" in value:
                            zz_value = re.search(value, res.text)
                            if zz_value:
                                extract_value = {key: zz_value.group(1)}
                                write_extract_yaml(extract_value)
                        else:
                            json_value = jsonpath.jsonpath(return_json, value)
                            if json_value:
                                extract_value = {key: json_value[0]}
                                write_extract_yaml(extract_value)
                # 断言
                if caseinfo['validate'] != "none":
                    yq_resulte = caseinfo['validate']
                    sj_resulte = return_json
                    self.assert_result(yq_resulte, sj_resulte, return_code)
                # 返回response对象
                return res
            else:
                print("二级关键字必须包含:method,url")
        else:
            print("一级关键字必须包含:name,request,validate")
    #统一请求封装
    def send_request(self, method, url, **kwargs):
        method = str(method).lower()
        url = self.replace_value(url)
        # 请求头和参数替换
        for key, value in kwargs.items():
            if key in ['params', 'data', 'json', 'headers']:
                kwargs[key] = self.replace_value(value)
                print(f"kwargs[key]:{kwargs[key]}")
            elif key == "files":
                for file_key, file_path in value.items():
                    value[file_key] = open(file_path, 'rb')
        res = RequestUtil.session.request(method,url,**kwargs)
        return res
    # 断言
    def assert_result(self, yq_result, sj_result, return_code):
        all_flag = 0
        for yq in yq_result:
            for key, value in yq.items():
                # print(key,value)
                if key == "equals":
                    flag = self.equals_assert(value, sj_result, return_code)
                    all_flag = all_flag + flag
                elif key == "contains":
                    flag = self.contains_assert(value, sj_result)
                    all_flag = all_flag + flag
                else:
                    print("框架暂不支持这种断言方式")
        assert all_flag == 0
    # 相等断言
    def equals_assert(self, value, sj_result, return_code):
        flag = 0
        for assert_key, assert_value in value.items():
            # print(assert_key,assert_value)
            if assert_key == "status_code":
                if assert_value != return_code:
                    flag = flag + 1
                    print("断言失败,返回的状态码不等于%s" % return_code)
            else:
                # list为实际json匹配出来的值
                lists = jsonpath.jsonpath(sj_result, '$..%s' % assert_key)
                if lists:
                    if assert_value not in lists:
                        flag = flag + 1
                        print(f"断言失败:{assert_key}不等于{assert_value}")
                else:
                    flag = flag + 1
                    print(f"断言失败:返回的结果不存在{assert_key}")
        return flag
    # 包含断言
    def contains_assert(self, value, sj_result):
        flag = 0
        if value not in str(sj_result):
            flag = flag + 1
            print(f"断言失败,返回结果中不包含{value}")
        return flag

修改pm_get_token.yaml,把要校验的validate内容填进去:​​​​​​​

-
  name: 获取token鉴权码
  request:
    method: get
    url: https://api.weixin.qq.com/cgi-bin/token
    params:
      grant_type: client_credential
      appid: wx8e8b67ced3c4b884
      secret: 27c524bd9ca932e31e229be30b0a805b
  validate:
    - equals: {status_code: 200}
    - equals: {expires_in: 7200}
    - contains: access_token
  extract:
    access_token: '"access_token":"(.*?)"'
    expires_in: $.expires_in

测试一下,断言成功生效:

自动化测试框架Pytest(八)——断言

断言失败生效:

自动化测试框架Pytest(八)——断言

接口测试重要的断言也就做好了。

最近太热了,发布完就去吃雪糕。

学习资源分享

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走

自动化测试框架Pytest(八)——断言

这些资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。希望对大家有所帮助…….【下方】

Original: https://blog.csdn.net/m0_58026506/article/details/126426152
Author: 静姐说测试
Title: 自动化测试框架Pytest(八)——断言

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/772079/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球