[接口测试_B] 14 pytest+requests实战练习2-参数化

上一篇://www.greatytc.com/p/d75f24e5de29

上一篇在一个py文件中,写了一堆test_开头的方法,所有数据和用例都在一个py文件中,本篇尝试读取json文件的测试数据,执行用例。

技术准备

  • httpbin:安装信息见上一篇
  • json:掌握json支持的数据格式和json的序列化操作
  • pytest:pytest的参数化方式
  • requests:requests是如何发送http请求的


    image.png

1、准备json格式的数据

  • httpbin中的示例接口都是比较简单的, 都没业务逻辑的关联啥的,按照requests.Request中要传入的参数准备的数据。
  • 可以把interface_info中的一个字典当作一个测试用例的数据。
# data.json
{
  "TestHttpMethods":
    {
      "interface_info": [
        {
          "interface_method": "get",
          "method": "get",
          "headers": null,
          "url_data": null,
          "data": {"test": "testdata"},
          "params": null,
          "auth": null,
          "cookies": null,
          "hooks": null,
          "json": null,
          "except": [200]
        },
        {
          "interface_method": "post",
          "method": "post",
          "headers": null,
          "url_data": null,
          "data": {"test": "testdata"},
          "params": null,
          "auth": null,
          "cookies": null,
          "hooks": null,
          "json": null,
          "except": [200]
        }
      ]
    },
  "TestAuth":
    {
      "interface_info": [
        {
          "interface_method": "basic-auth",
          "method": "get",
          "headers": null,
          "url_data": ["testuser", "testpasswd"],
          "data": null,
          "params": null,
          "auth": ["testuser", "testpasswd"],
          "cookies": null,
          "hooks": null,
          "json": null,
          "except": [200]
        },
        {
          "interface_method": "bearer",
          "method": "get",
          "headers": {"Authorization": "justtestauth"},
          "url_data": null,
          "data": null,
          "params": null,
          "auth": null,
          "cookies": null,
          "hooks": null,
          "json": null,
          "except": [200]
        }
      ]
    }
}

2、读取json文件中的数据

  • get_case(): 用于读取json文件中的数据,并保存为字典格式,最后用yield返回一个生成器
  • get_data(): 用于解析字典中的数据,由于后续要采用pytest中的@pytest.mark.parametrize进行参数化,所以把每组数据都保持在一个元组中,元组存于列表中
# conftest.py
import sys
sys.path.append('.')

import json, codecs, os
print(os.getcwd())

def get_case():
    with codecs.open('data.json', 'r', encoding='utf-8') as f:
        f_dict = json.load(f)
        for collection, cases in f_dict.items():
            for case in cases['interface_info']:
                yield {collection: case}

def get_data():
    cases = get_case()
    datas = []
    for case_d in cases:
        for collection, case in case_d.items():
            url_method = case['interface_method']
            method = case['method']
            headers = case["headers"]
            url_data = case['url_data'] # if case['url_data'] is None else tuple(case['url_data'])
            data = case['data']
            params = case['params']
            auth = case['auth']
            cookies = case['cookies']
            hooks = case['hooks']
            json = case['json']
            except_data = case['except']
            t = (url_method, method, headers, url_data, data, params, auth, cookies, hooks, json, except_data)
            datas.append(t)

    return datas

结果:

print(type(get_case()))
print(get_data())
<class 'generator'>
[('get', 'get', None, None, {'test': 'testdata'}, None, None, None, None, None, [200]), 
('post', 'post', None, None, {'test': 'testdata'}, None, None, None, None, None, [200]), 
('basic-auth', 'get', None, ['testuser', 'testpasswd'], None, None, ['testuser', 'testpasswd'], None, None, None, [200]), 
('bearer', 'get', {'Authorization': 'justtestauth'}, None, None, None, None, None, None, None, [200])]

3、重写一下requests的请求方法

  • 由于在json文件中,写入了接口路径的path部分和接口的请求方法,所以选择requests.Request()方法发送请求,参照Request的源码,将需要传入的参数都在__init__()构造方法中进行初始化
  • 可以看到__init__()中用了非常经典的三语表达式
  • 因为url_data和auth在json中传入的是列表,但是参数需要的实际格式是元组,所以当传入的参数不是None时,需要转换为元组
  • 这个文件中,导入了一个config.py文件,里面现在就一个参数BASE_URL = 'http://192.168.68.128:8088/',主要用于存储一些配置信息(如果后面发邮件或者连数据库啥的,配置信息也可以写在这里面)
  • url拼接:httpbin中,某些接口的url需要传入与auth数据一致的信息,所以采用urljoin进行拼接
# httpmethods.py
import sys
sys.path.append('.')
from urllib.parse import urljoin

import requests
from requests import Request, Session

import config

# print(config.BASE_URL)
class Http:
    def __init__(self,
                 method=None, url=None, headers=None, files=None, data=None,
                 params=None, auth=None, cookies=None, hooks=None, json=None,
                 base_url=None, url_method=None, url_data=None):
        # Default empty dicts for dict params.
        data = [] if data is None else data
        files = [] if files is None else files
        headers = {} if headers is None else headers
        params = {} if params is None else params
        hooks = {} if hooks is None else hooks
        url_data = () if url_data is None else tuple(url_data)
        auth = None if auth is None else tuple(auth)

        self.hooks = requests.hooks.default_hooks()
        type(hooks)
        for (k, v) in list(hooks.items()):
            Request.register_hook(event=k, hook=v)

        self.method = method
        self.url = url
        self.headers = headers
        self.files = files
        self.data = data
        self.json = json
        self.params = params
        self.auth = auth
        self.cookies = cookies
        self.base_url = base_url
        self.url_method = url_method
        self.url_data = url_data

    def method_new(self):
        self.base_url = config.BASE_URL
        s = Session()
        url = urljoin(self.base_url, '/'.join((self.url_method,) + self.url_data))
        print(url)
        req = Request(method=self.method.upper(), url=url, headers=self.headers,
                    files=self.files, data=self.data, params=self.params, auth=self.auth,
                    cookies=self.cookies, json=self.json)
        prepped = req.prepare()
        # 如果需要设置代理,可以在s.send中添加并进行配置, 详情查看send的源码
        resp = s.send(prepped)
        return resp

4、采用pytest进行参数化

  • 导入前面准备的文件,采用pytest.mark.parametrize进行参数化
  • 实例化重写的请求发送方式,并传入参数化数据
  • 发送请求,接收结果并进行断言
# test_run.py
import sys
sys.path.append('.')

import pytest

from httpmethods import Http
import conftest

@pytest.mark.parametrize("url_method, method, headers, url_data, data, params, auth, cookies, hooks, json, except_data",
                         conftest.get_data())
def test_case(url_method, method, headers, url_data, data, params, auth, cookies, hooks, json, except_data):
    h = Http(method=method, url_method=url_method, headers=headers,
             url_data=url_data, data=data, params=params, auth=auth,
             cookies=cookies, hooks=hooks, json=json)
    r = h.method_new()
    assert r.status_code == except_data[0]

5、运行pytest命令,执行用例生成测试报告

pytest -q --tb=no --html=./report.html

总结

  • 往前的一小步:学会了json文件的读取,虽然我觉得之前也是会的,但是在实际练习过程中发现,对json支持的数据类型与python之间的转换认识得仍然不够深入:


    image.png
  • 不足之处:
    1、从json文件可以看出,TestHttpMethods和TestAuth存在的目的是想要表示一个测试集,但是在用例实际执行过程中没有体现出来,对于pytest的使用不熟练,还不知道应该如何结合起来;
    2、在命令行中使用pytest的命令执行用例的方式不够灵活;
    3、邮件发送、定时任务执行等等,都是必要的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,226评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,509评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,523评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,181评论 1 302
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,189评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,642评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,993评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,977评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,527评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,547评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,661评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,250评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,991评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,422评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,571评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,241评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,737评论 2 366

推荐阅读更多精彩内容