pytest--函数传参和fixture传参数request
前言
为了提高代码的复用性,我们在写用例的时候,会用到函数,然后不同的用例去调用这个函数。
比如登录操作,大部分的用例都会先登录,那就需要把登录单独抽出来写个函数,其它用例全部的调用这个登录函数就行。但是登录的账号不能写死,有时候我想用账号1去登录,执行用例1,用账号2去登录执行用例2,所以需要对函数传参。
登录函数传参
把登录单独出来,写一个函数,传2个参数user和pwd,写用例的时候调用登录函数,输入几组user,pwd参数化登录用例测试用例传参需要用装饰器@pytest.mark.parametrize,里面写两个参数。
第一个参数是字符串,多个参数中间用逗号隔开
第二个参数是list,多组数据用元组类型
#test_fix1.py
#coding:utf-8
import pytest
test_user_data=[("admin","123456"),("test","")]
def login(user,pwd):
print("登录账号:{}".format(user))
print("登录密码:%s"%pwd)
if pwd:
return True
else:
return False
@pytest.mark.parametrize("user,pwd",test_user_data)
def test_login(user,pwd):
result=login(user,pwd)
assert result==True,"失败原因:密码为空"
if __name__=="__main__":
pytest.main(["-s","test_fix1.py"])
运行结果
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: D:\study\xyautotest
plugins: allure-pytest-2.8.19, Faker-4.18.0, hypothesis-6.14.6, assume-2.4.3, forked-1.3.0, html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1, xdist-2.3.0, tep-0.8.9collected 2 items
test_f1.py .登录账号:admin
登录密码:123456
F登录账号:test
登录密码:
AssertionError: 失败原因:密码为空
False != True
Expected :True
Actual :False
<Click to see difference>
user = 'test', pwd = ''
@pytest.mark.parametrize("user,pwd",test_user_data)
def test_login(user,pwd):
result=login(user,pwd)
> assert result==True,"失败原因:密码为空"
E AssertionError: 失败原因:密码为空
E assert False == True
test_f1.py:13: AssertionError
Assertion failed
[100%]
================================== FAILURES ===================================
______________________________ test_login[test-] ______________________________
user = 'test', pwd = ''
@pytest.mark.parametrize("user,pwd",test_user_data)
def test_login(user,pwd):
result=login(user,pwd)
> assert result==True,"失败原因:密码为空"
E AssertionError: 失败原因:密码为空
E assert False == True
test_f1.py:13: AssertionError
---------------------------- Captured stdout call -----------------------------
登录账号:test
登录密码:
=========================== short test summary info ===========================
FAILED test_f1.py::test_login[test-] - AssertionError: 失败原因:密码为空
========================= 1 failed, 1 passed in 0.27s =========================
Process finished with exit code 0
从结果可以看出,有2个用例,一个测试通过,一个测试失败了,互不影响。
request参数
如果想把登录操作放到前置操作里,也可以用到@pytest.fixture装饰器,传参就用默认的request参数user=request.param这一步是接收传入的参数,如下传入一个参数情况。
添加indirect=True参数是为了把login当成一个函数去执行,而不是一个参数.
indirect=True是指用test_users数据对"login"这个fixture进行参数化,虽然装饰器写在测试用例上,但是却是对测试用例使用的fixture进行传递数据,这正是indirect单词的意思。
#coding:utf-8
import pytest
test_users=["admin","test",""]
@pytest.fixture(scope="module")
def login(request):
user=request.param
print(f"登录账户:{user}")
return user
@pytest.mark.parametrize("login",test_users,indirect=True)
def test_login(login):
a=login
print(f"测试用例中login的返回值{a}")
assert a !="","账户为空"
if __name__=="__main__":
pytest.main(["-s","test_fix1.py"])
运行结果
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: D:\study\xyautotest
plugins: allure-pytest-2.8.19, Faker-4.18.0, hypothesis-6.14.6, assume-2.4.3, forked-1.3.0, html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1, xdist-2.3.0, tep-0.8.9collected 3 items
test_f1.py 登录账户:admin
.测试用例中login的返回值admin
登录账户:test
.测试用例中login的返回值test
登录账户:
F测试用例中login的返回值
test_f1.py:8 (test_login[])
login = ''
@pytest.mark.parametrize("login",test_users,indirect=True)
def test_login(login):
a=login
print(f"测试用例中login的返回值{a}")
> assert a !="","账户为空"
E AssertionError: 账户为空
E assert '' != ''
test_f1.py:13: AssertionError
[100%]
================================== FAILURES ===================================
________________________________ test_login[] _________________________________
login = ''
@pytest.mark.parametrize("login",test_users,indirect=True)
def test_login(login):
a=login
print(f"测试用例中login的返回值{a}")
> assert a !="","账户为空"
E AssertionError: 账户为空
E assert '' != ''
test_f1.py:13: AssertionError
---------------------------- Captured stdout setup ----------------------------
登录账户:
---------------------------- Captured stdout call -----------------------------
测试用例中login的返回值
=========================== short test summary info ===========================
FAILED test_f1.py::test_login[] - AssertionError: 账户为空
========================= 1 failed, 2 passed in 0.27s =========================
Process finished with exit code 0
request传2个参数
如果用到@pytest.fixture,里面用2个参数情况,可以把多个参数用一个字典去存储,这样最终还是只传一个参数。
不同的参数再从字典里面取对应key值就行,如:user=request.param["user"]
#test_fix1.py
#coding:utf-8
import pytest
test_users=[{"user":"admin","pwd":"123456"},{"user":"test","pwd":""}]
@pytest.fixture(scope="module")
def login(request):
user=request.param["user"]
pwd=request.param["pwd"]
print(f"登录账户:{user}")
print(f"登录密码:{pwd}")
return pwd
@pytest.mark.parametrize("login",test_users,indirect=True)
def test_login(login):
a=login
print("测试用例中login的返回值{}".format(a))
assert a !="","密码为空"
if __name__=="__main__":
pytest.main(["-s","test_fix1.py"])
运行结果
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: D:\study\xyautotest
plugins: allure-pytest-2.8.19, Faker-4.18.0, hypothesis-6.14.6, assume-2.4.3, forked-1.3.0, html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1, xdist-2.3.0, tep-0.8.9collected 2 items
test_f1.py 登录账户:admin
登录密码:123456
.测试用例中login的返回值123456
登录账户:test
登录密码:
F测试用例中login的返回值
test_f1.py:11 (test_login[login1])
login = ''
@pytest.mark.parametrize("login",test_users,indirect=True)
def test_login(login):
a=login
print("测试用例中login的返回值{}".format(a))
> assert a !="","密码为空"
E AssertionError: 密码为空
E assert '' != ''
test_f1.py:16: AssertionError
Assertion failed
[100%]
================================== FAILURES ===================================
_____________________________ test_login[login1] ______________________________
login = ''
@pytest.mark.parametrize("login",test_users,indirect=True)
def test_login(login):
a=login
print("测试用例中login的返回值{}".format(a))
> assert a !="","密码为空"
E AssertionError: 密码为空
E assert '' != ''
test_f1.py:16: AssertionError
---------------------------- Captured stdout setup ----------------------------
登录账户:test
登录密码:
---------------------------- Captured stdout call -----------------------------
测试用例中login的返回值
=========================== short test summary info ===========================
FAILED test_f1.py::test_login[login1] - AssertionError: 密码为空
========================= 1 failed, 1 passed in 0.27s =========================
Process finished with exit code 0
Assertion failed
Assertion failed
如果要用到login里面的返回值,def test_login(login)时,传入login参数,函数返回值就是login了。
多个fixtrue
用例上面是可以同时放多个fixture的,也就是多个前置操作,可以支持装饰器叠加,使用parametrize装饰器叠加时,用例组合是2个参数个数相乘。
#test_fix1.py
#coding:utf-8
import pytest
test_users=["admin","test"]
test_pwd=["123456","888888"]
@pytest.fixture(scope="module")
def in_user(request):
user=request.param
print("登录账号:{}".format(user))
return user
@pytest.fixture(scope="module")
def in_pwd(request):
pwd=request.param
print("登录密码:{}".format(pwd))
return pwd
@pytest.mark.parametrize("in_user",test_users,indirect=True)
@pytest.mark.parametrize("in_pwd",test_pwd,indirect=True)
def test_login(in_user,in_pwd):
a=in_user
b=in_pwd
print("账号,密码:{},{}".format(a,b))
assert b
if __name__=="__main__":
pytest.main(["-s","test_fix1.py"])
运行结果:
============================= test session starts =============================
platform win32 -- Python 3.8.2, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: D:\study\xyautotest
plugins: allure-pytest-2.8.19, Faker-4.18.0, hypothesis-6.14.6, assume-2.4.3, forked-1.3.0, html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1, xdist-2.3.0, tep-0.8.9collected 4 items
test_f1.py [100%]
============================== 4 passed in 0.12s ==============================
Process finished with exit code 0
登录账号:admin
登录密码:123456
.账号,密码:admin,123456
登录账号:test
.账号,密码:test,123456
登录密码:888888
.账号,密码:test,888888
登录账号:admin
.账号,密码:admin,888888
如果参数users有2个数据,参数pwd有2个数据,那么组合起来的案例是两个相乘,也就是2*2=4个用例