zoukankan      html  css  js  c++  java
  • pytest文档73-pytest+yaml实现接口自动化框架之用例参数关联

    前言

    使用 yaml 文件写测试用例的时候,如何在 yaml 文件的测试用例里面实现参数关联? 这是很多做自动化测试的小伙伴经常思考的一个问题。
    接着前面的pytest+yaml 文件实现接口自动化框架,本篇使用环境变量的方式,让测试用例参数关联。
    实现场景:上个接口返回的接口提取变量,在写个接口中引用变量

    场景案例

    我现在有一个登陆接口A,登陆成功后返回一个token值。有一个获取用户信息的接口B,但是接口B必须要先登录后传登录的token才能访问
    A接口登录接口文档基本信息

    B接口获取绑定卡号的接口文档基本信息

    • 访问地址:http://127.0.0.1:8000/api/v1/userinfo/
    • 请求类型:GET
    • 请求头部:Content-Type: application/json
    • 请求头部token参数: Authorization: Token xxxxx login token xxxxx

    先不带token去访问接口B,使用命令行工具httpie测试接口

    C:Usersdell>http http://127.0.0.1:8000/api/v1/user/info/
    HTTP/1.1 401 Unauthorized
    Allow: GET, POST, HEAD, OPTIONS
    Content-Length: 58
    Content-Type: application/json
    Date: Sat, 21 Sep 2019 14:06:15 GMT
    Server: WSGIServer/0.2 CPython/3.6.0
    Vary: Accept
    WWW-Authenticate: Token
    X-Frame-Options: SAMEORIGIN
    
    {
        "detail": "Authentication credentials were not provided."
    }
    

    不带token会提示没权限访问:401 Unauthorized

    接口测试

    先使用接口测试工具测试下,用postman,或者fiddler都可以,我这里为了查看报文信息方便,用httpie命令行工具

    先访问接口A获取token值234af73571da46ade79ea6a74961b1d23d609b79

    D:>http http://127.0.0.1:8000/api/v1/login/ username=test password=123456 -v
    POST /api/v1/login/ HTTP/1.1
    Accept: application/json, */*
    Accept-Encoding: gzip, deflate
    Connection: keep-alive
    Content-Length: 42
    Content-Type: application/json
    Host: 127.0.0.1:8000
    User-Agent: HTTPie/1.0.3
    
    {
        "password": "123456",
        "username": "test"
    }
    
    HTTP/1.1 200 OK
    Allow: POST, OPTIONS
    Content-Length: 109
    Content-Type: application/json
    Date: Sat, 21 Sep 2019 15:37:06 GMT
    Server: WSGIServer/0.2 CPython/3.6.0
    Vary: Accept, Cookie
    X-Frame-Options: SAMEORIGIN
    
    {
        "code": 0,
        "msg": "login success!",
        "token": "234af73571da46ade79ea6a74961b1d23d609b79",
        "username": "test"
    }
    

    传给下个接口B

    D:>http http://127.0.0.1:8000/api/v1/user/info/ Authorization:"Token b7e02c959fbae4c2a0d9094f6f9b9a35fa8aaa1e" -v
    GET /api/v1/user/info/ HTTP/1.1
    Accept: */*
    Accept-Encoding: gzip, deflate
    Authorization: Token b7e02c959fbae4c2a0d9094f6f9b9a35fa8aaa1e
    Connection: keep-alive
    Host: 127.0.0.1:8000
    User-Agent: HTTPie/1.0.3
    
    
    
    HTTP/1.1 200 OK
    Allow: GET, POST, HEAD, OPTIONS
    Content-Length: 96
    Content-Type: application/json
    Date: Sat, 21 Sep 2019 16:04:25 GMT
    Server: WSGIServer/0.2 CPython/3.6.0
    Vary: Accept
    X-Frame-Options: SAMEORIGIN
    
    {
    	"msg": "sucess!",
    	"code": 0,
    	"data": [{
    		"id": 15,
    		"name": "test",
    		"sex": "F",
    		"age": 20,
    		"mail": "1122@qq.com",
    		"create_time": "2020-12-18"
    	}]
    }
    

    传头部参数用xx:xxxx格式,中间用冒号:,如:User-Agent:demo-agent/1.0 'Cookie:a=b;b=c' ,由于Authorization参数中间有空格,用双引号包起来

    conftest.py 代码实现

    在 conftest.py 使用环境变量保存测试的结果提取的变量,使用 template 替换 yaml 文件的变量

    import pytest
    import requests
    import jsonpath
    import json
    import yaml
    from string import Template
    import os
    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    def pytest_collect_file(parent, path):
        # 获取文件.yml 文件,匹配规则
        if path.ext == ".yml" and path.basename.startswith("test"):
            print(path)
            print(parent)
            return YamlFile(path, parent)
    
    
    class YamlFile(pytest.File):
        '''收集测试用例'''
        def collect(self):
            yml_raw = self.fspath.open(encoding='utf-8').read()
            yml_var = Template(yml_raw).safe_substitute(os.environ)
            yaml_data = yaml.safe_load(yml_var)
            for yaml_case in yaml_data:
                name = yaml_case.get("test").get("name")
                values = yaml_case.get("test")
                yield YamlTest(name, self, values)
    
    
    class YamlTest(pytest.Item):
        def __init__(self, name, parent, values):
            super(YamlTest, self).__init__(name, parent)
            self.name = name
            self.values = values
            self.s = requests.session()
    
        def values_render_variable(self, values):
            # values 是Test用例部分
            yaml_test = Template(json.dumps(values)).safe_substitute(os.environ)
            values = yaml.safe_load(yaml_test)
            return values
    
        def runtest(self):
            # 运行用例
            values = self.values_render_variable(self.values)
            request_data = values.get("request")
            print("
    请求数据: ", request_data)
            print(request_data)
            response = self.s.request(**request_data)
            print("接口返回", response.text)
            # 判断是否有extract提取参数
            if values.get("extract"):
                for key, value in values.get("extract").items():
                    os.environ[key] = jsonpath.jsonpath(response.json(), value)[0]
            self.assert_response(response, values.get("validate"))
    
        def assert_response(self, response, validate):
            '''设置断言'''
            if validate:
                for i in validate:
                    if "eq" in i.keys():
                        yaml_result = i.get("eq")[0]
                        actual_result = jsonpath.jsonpath(response.json(), yaml_result)
                        expect_result = i.get("eq")[1]
                        print("实际结果:%s" % actual_result[0])
                        print("期望结果:%s" % expect_result)
                        assert actual_result[0] == expect_result
    
    

    YAML 文件案例

    使用 extract 关键字提取变量,提取变量方式执行jsonpath表达式, 引用变量使用template 模板的引用语法$变量名

    # 作者-上海悠悠 QQ交流群:717225969
    # blog地址 https://www.cnblogs.com/yoyoketang/
    
    - test:
        name: login case1
        request:
            url: http://49.235.X.X:7000/api/v1/login/
            method: POST
            headers:
                Content-Type: application/json
                User-Agent: python-requests/2.18.4
            json:
                username: test
                password: 123456
        extract:
            token: $.token
        validate:
            - eq: [$.msg, login success!]
            - eq: [$.code, 0]
    
    - test:
        name: get user info case1
        request:
            url: http://49.235.X.X:7000/api/v1/userinfo/
            method: GET
            headers:
                Content-Type: application/json
                User-Agent: python-requests/2.18.4
                Authorization: Token $token
        validate:
            - eq: [$.code, 0]
            - eq: ["$.data[0].name", test]
            - eq: ["$.data[0].mail", 1122@qq.com]
    

    执行结果

    执行方式使用命令行运行,支持pytest的命令行指令

    pytest

    运行结果

    >pytest -s
    ============================= test session starts ==============================
    platform win32 -- Python 3.6.6, pytest-4.5.0, py-1.9.0, pluggy-0.13.1
    rootdir: D:softapi_pytest_1208
    collecting ... D:softapi_pytest_1208data	est_info.yml
    <Package D:softapi_pytest_1208data>
    collected 2 items
    
    data	est_info.yml
    请求数据:  {'url': 'http://49.235.X.X:7000/api/v1/login/', 'method': 'POST', 
    'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4'}, 
    'json': {'username': 'test', 'password': 123456}}
    {'url': 'http://49.235.X.X:7000/api/v1/login/', 'method': 'POST', 
    'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4'},
     'json': {'username': 'test', 'password': 123456}}
    接口返回 {"code": 0, "msg": "login success!", "username": "test", "token": "09be4368534fa6320ed77a333e34c6661a36d40e"}
    实际结果:login success!
    期望结果:login success!
    实际结果:0
    期望结果:0
    .
    请求数据:  {'url': 'http://49.235.X.X:7000/api/v1/userinfo/', 'method': 'GET', 
    'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 
    'Authorization': 'Token 09be4368534fa6320ed77a333e34c6661a36d40e'}}
    {'url': 'http://49.235.X.X:7000/api/v1/userinfo/', 'method': 'GET', 
    'headers': {'Content-Type': 'application/json', 'User-Agent': 'python-requests/2.18.4', 
    'Authorization': 'Token 09be4368534fa6320ed77a333e34c6661a36d40e'}}
    接口返回 {"msg":"sucess!","code":0,"data":[{"id":15,"name":"test","sex":"F","age":20,"mail":"1122@qq.com","create_time":"2020-12-18"}]}
    实际结果:0
    期望结果:0
    实际结果:test
    期望结果:test
    实际结果:1122@qq.com
    期望结果:1122@qq.com
    .
    
    =========================== 2 passed in 0.49 seconds ===========================
    
    
  • 相关阅读:
    Winform跨线程操作界面的策略
    Winform DataGridView扩展
    GDI+的常用类
    函数中参数的验证顺序
    C# Winform常见的Editor及其它经验
    能够引起异常的运算符和关键字
    终结程序
    C#异常处理策略
    python3.6入门到高阶(全栈) day01 python 基础
    虚拟机中系统盘扩容
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/14154379.html
Copyright © 2011-2022 走看看