先说经验总结

实操:[造数函数] 和 [测试用例] 都需要调用登录接口获取用户 token,既然都需要调用登录接口,那会不会出现 token 失效的情况呢?

例如有一个订单查询接口 orderList,调用 orderList 需要传入的参数为:token、orderType、submitState、page 和 limit,其中 submitState 的可选值是固定的 [None,1,2],orderType 的可选值是由接口 getOrderType 返回的,调用 getOrderType 需要传入 token。在这种场景下设计用例就引发了一系列的思考。

首先我共有三个.py 文件,test.py,conftest.py 和 case_data.py,内容大致如下:

在写 case_data 时,先后共写过两个版本,我描述一下思考过程,当前为第一个版本。

# conftest.py
@pytest.fixture(scope="session")
def tf_stu_token():
    base_url = Environment.HOST_LAPI + 'login'
    data = {
            'userphone': Environment.userphone_stu,
            'password': CT.to_md5(Environment.password_stu),
            'phonecode': 86,
            'type': 1
            }
    resp = requests.post(url=base_url, data=data)
    assert resp.status_code == 200
    token = resp.json()["data"]["token"]
    return token
# case_data.py V1

def getOrderType(tf_stu_token):  # !问题就出在这里,在非测试函数的地方引用fixture并不会生效,但当时不知道
    url = Environment.HOST_LAPI + 'getOrderType'
    data = {
        'token':tf_stu_token,
    }
    resp = requests.post(url=url,data=data)
    return resp.json()['data']  # 会返回[0,1,2,3,4]

def data_orderList():
    total = []

    orderType_list = getOrderType()
    submitState_list = [None,1,2]

    for i in range(5):
        item = []
        case = {}
        case['OrderType'] = orderType_list[i % len(orderType_list)]
        case['submitState'] = submitState_list[i % len(submitState_list)]

        item.append(case)

        expect = {}
        expect['code'] = 2000
        item.append(expect)

        item.append('正常入参')

        total.append(item)

    # token为空
    total.append([{'OrderType': 0,'submitState': None}, {'code': 4001}, 'token为空'])

    return total

'''
这个total最终为包含6条测试数据的列表:
 [
    [{'OrderType': 0,'submitState': None}, {'code': 2000}, '正常入参'],
    [{'OrderType': 1,'submitState': 1}, {'code': 2000}, '正常入参'],
    [{'OrderType': 2,'submitState': 2}, {'code': 2000}, '正常入参'],
    [{'OrderType': 3,'submitState': None}, {'code': 2000}, '正常入参'],
    [{'OrderType': 4,'submitState': 1}, {'code': 2000}, '正常入参'],
    [{'OrderType': 0,'submitState': None}, {'code': 4001}, 'token为空']
]
'''
# test.py
import pytest
import requests
import case_data as CD

@ pytest.mark.parametrize("case, expect, desc", CD.data_orderList())
def test_orderList(tf_stu_token, case, expect, desc):
    url = Environment.HOST_LAPI + 'orderList'
    data = {
        'token': tf_stu_token,
        'orderType':case['orderType'],
        'submitState':case['submitState'],
        'page': 1,
        'limit': 20
    }
    resp = requests.post(url=url, data=data)
    assert resp.json()['code'] == expect['code']

测试后发现,造数函数报错,原因是调用 getOrderType 时缺少参数 tf_stu_token。当时就很纳闷,我隐约记得 fixture 函数不需要显式调用呀,不应该是运行的时候会自动加载么。报错信息大致如下:

查阅后发现,pytest 会在测试函数中调用时自动查找具有相同名称的 fixture,并将其注入到测试函数中。非测试函数并不能使用 fixture。 也有资料说 fixture 可以被非测试函数调用,但几经实践后并没有成功。
于是为了在 case_data.py 中获取 token,我决定在 case_data.py 中再另行调用一遍登录接口。修改后的 case_data.py 如下:

# case_data.py V2

def get_stu_token(userphone, password):
    base_url = Environment.HOST_LAPI + 'login'
    data = {'userphone': userphone,
            'password': CT.to_md5(password),
            'phonecode': 86,
            'type': 1
            }
    response = requests.post(url=base_url, data=data)
    token = response.json()["data"]["token"]
    return token

token_stu = get_stu_token(Environment.userphone_stu, Environment.password_stu)

def getOrderType():  # !问题就出在这里,在非测试函数的地方引用fixture并不会生效,但当时不知道
    url = Environment.HOST_LAPI + 'getOrderType'
    data = {
        'token':token_stu,
    }
    resp = requests.post(url=url,data=data)
    return resp.json()['data']  # 会返回[0,1,2,3,4]

def data_orderList():
    total = []

    orderType_list = getOrderType()
    submitState_list = [None,1,2]

    for i in range(5):
        item = []
        case = {}
        case['OrderType'] = orderType_list[i % len(orderType_list)]
        case['submitState'] = submitState_list[i % len(submitState_list)]

        item.append(case)

        expect = {}
        expect['code'] = 2000
        item.append(expect)

        item.append('正常入参')

        total.append(item)

    # token为空
    total.append([{'OrderType': 0,'submitState': None}, {'code': 4001}, 'token为空'])

    return total

运行后可以正常运行,但我当时心中又有一个疑问,我在造数脚本里调用登录接口,会不会导致测试脚本里的 token 失效?经过实践后得到结论:在造数函数中调用登录接口并不会致使测试脚本中的 token 失效,原因是pytest 在执行测试时会先进行测试用例的收集,然后再执行测试,放在当前情景中,如果有影响,也是测试用例中调用登录接口后会致使造数脚本中的 token 失效,可造数接口已经提供完价值了,token 失不失效也没有任何影响了。

文中提到的参数化用的是@pytest.mark.parametrize,可能由于编辑器问题,发布后变成了@user5ize,所以我在 @ 后增加了一个空格


↙↙↙阅读原文可查看相关链接,并与作者交流