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:\Users\dell>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("\n請求數據: ", 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:\soft\api_pytest_1208
collecting ... D:\soft\api_pytest_1208\data\test_info.yml
<Package D:\soft\api_pytest_1208\data>
collected 2 items

data\test_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 ===========================


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM