菜单
本页目录

问题背景

因为测试用例的多样性,我们不能硬编码,比如登录的fixture,不能只写入固定的登录用户名和密码,一个是不方便后期维护,另外一个是不好拓展。

在之前的代码中我们发现,fixture是没办法直接传参的,举个例子:

import pytest


@pytest.fixture
def login(name ,password):
    print(f"用户{name},使用密码{password}登录成功")



def test_01(login):
    login("admin","123456")
    print("正在执行test01")

def test_02(login):
    login("user01","666666")
    print("正在执行test02")


if __name__ == '__main__':
    pytest.main(['fixture传参.py', '-s'])

目的很简单,执行casetest_01的时候使用admin账号,执行casetest_02的时候,使用user01的账号。但是 执行的时候就报错了:

@pytest.fixture
def login(name ,password):
E       fixture 'name' not found

好像fixture 默认接受的参数必须是另外一个fixture,但是又不存在另外一个叫name的fixture,所以此时就报异常。

所以,为了解决这一问题,我们要学习新的知识点:@pytest.mark.parametrize

@pytest.mark.parametrize传递参数

之前在讲fixture的参数 params的时候,讲到过request的使用:

import pytest


# 定义的夹具函数,使用装饰器pytest.fixture
@pytest.fixture(params=["胡八万","胡三条","胡七筒"])
def login(request):
    temp = request.param
    print(f"login:用户{temp}执行登录操作")

    return temp


#当fixture 的params参数 会被循环执行
def test_01(login):
    print(f"{login}已经登录成功~")


if __name__ == '__main__':
    pytest.main(['MyPytest.py', '-s'])

执行结果:

collected 3 items

MyPytest.py login:用户胡八万执行登录操作
胡八万已经登录成功~
.login:用户胡三条执行登录操作
胡三条已经登录成功~
.login:用户胡七筒执行登录操作
胡七筒已经登录成功~
.

============================== 3 passed in 0.07s ==============================

***Repl Closed***

request是fixture的传参的固定写法

为了解决上述问题,我们使用@pytest.mark.parametrize配合request可以完美解决:

import pytest


@pytest.fixture
def login(request):
    param = request.param
    print(f"用户{param['name']},使用密码{param['password']}登录成功")


data01 = [{'name': 'admin', 'password': '123456'}]

@pytest.mark.parametrize("login", data01, indirect=True)
def test_01(login):
    print("正在执行test01")


data02 = [{'name': 'user01', 'password': '666666'}]

@pytest.mark.parametrize("login", data02, indirect=True)
def test_02(login):
    print("正在执行test02")


if __name__ == '__main__':
    pytest.main(['fixture传参.py', '-s'])

执行结果:

collected 2 items

fixture传参.py 

用户admin,使用密码123456登录成功
正在执行test01
.
用户user01,使用密码666666登录成功
正在执行test02
.

============================== 2 passed in 0.07s ==============================

***Repl Closed***

参数讲解

indirect = True是将login作为一个函数去执行,而不是一个参数,data则是这个函数的入参。

data本质是一个列表,如果入参是fixture是单个入参,则data可以定义为:

data = ["key1","key2",... ...]

那么执行case则遍历执行key1key2

如果fixture是多个参数的入参,则data需要传入字典形式:

data=[{"key1":"value1"},{"key2":"value2"}... ... ]

同理函数遍历执行{"key1":"value1"},{"key2":"value2"}的场景

使用多个fixture的入参

@pytest.mark.parametrize 叠加使用
import pytest


@pytest.fixture
def openBrowser(request):
    """打开不同类型的浏览器"""
    browserType = request.param
    print(f"正在使用{browserType}浏览器")


@pytest.fixture
def login(request):
    param = request.param
    print(f"用户{param['name']},使用密码{param['password']}登录成功")


browserTypes = ["IE"]
userInfo = [{'name': 'admin', 'password': '123456'}]


@pytest.mark.parametrize("login", userInfo, indirect=True)
@pytest.mark.parametrize("openBrowser", browserTypes, indirect=True)
def test_01(openBrowser, login):
    print("正在执行test01")


if __name__ == '__main__':
    pytest.main(['fixture传参.py', '-s'])

运行结果:

collected 1 item

fixture传参.py 
正在使用IE浏览器
用户admin,使用密码123456登录成功
正在执行test01
.

============================== 1 passed in 0.07s ==============================

***Repl Closed***
@pytest.mark.parametrize 合并使用
import pytest


@pytest.fixture
def openBrowser(request):
    """打开不同类型的浏览器"""
    browserType = request.param
    print(f"正在使用{browserType}浏览器")


@pytest.fixture
def login(request):
    param = request.param
    print(f"用户{param['name']},使用密码{param['password']}登录成功")


data = [('IE', {'name': 'admin', 'password': '123456'})]


@pytest.mark.parametrize("openBrowser,login", data, indirect=True)
def test_01(openBrowser, login):
    print("正在执行test01")


if __name__ == '__main__':
    pytest.main(['fixture传参.py', '-s'])

执行结果:

fixture传参.py 
正在使用IE浏览器
用户admin,使用密码123456登录成功
正在执行test01
.
============================== 1 passed in 0.07s ==============================

***Repl Closed***

如果我们想测试多种场景即可改动data的数据,进行参数化:

import pytest


@pytest.fixture
def openBrowser(request):
    """打开不同类型的浏览器"""
    browserType = request.param
    print(f"正在使用{browserType}浏览器")


@pytest.fixture
def login(request):
    param = request.param
    print(f"用户{param['name']},使用密码{param['password']}登录成功")


data = [('IE', {'name': 'admin', 'password': '123456'}),('IE', {'name': 'root', 'password': '888888'}),('Chrome', {'name': 'admin', 'password': '123456'})]


@pytest.mark.parametrize("openBrowser,login", data, indirect=True)
def test_01(openBrowser, login):
    print("正在执行test01")


if __name__ == '__main__':
    pytest.main(['fixture传参.py', '-s'])

执行结果:

fixture传参.py 正在使用IE浏览器
用户admin,使用密码123456登录成功
正在执行test01
.正在使用IE浏览器
用户root,使用密码888888登录成功
正在执行test01
.正在使用Chrome浏览器
用户admin,使用密码123456登录成功
正在执行test01
.

============================== 3 passed in 0.07s ==============================

***Repl Closed***