fixture的作用:作用类似unittest中setup/teardown,它的优势是可以跨文件共享
fixture的格式:在普通函数上加上装饰器@pytest.fixture(),且函数名不能以test_开头,目的是与测试用例做区分
一 fixture的三种调用方式
1.在测试用例中 直接把fixture的函数名称作为参数传入 进行调用
fixture如何使用?fixture可以有返回值,如果没有return默认但会None;用例调用fixture的返回值,就是直接把fixture的函数名称作为参数传入。
特别说明:用例断言失败是failed,fixture断言失败是error
fixture的作用范围
demo1:fixture可以返回一个元组、列表或字典
# test_01.py import pytest @pytest.fixture() def user(): print("用户名") name = 'wangmm' password = '123456' return name,password def test_a(user): u = user[0] p = user[1] assert u == 'wangmm' 执行结果: D:myprojectpytest_demo estcases>pytest -vs test_01.py =================================================================================== test session starts ==================================================================================== platform win32 -- Python 3.6.5, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 -- d:softpython36python.exe cachedir: .pytest_cache rootdir: D:myprojectpytest_demo estcases collected 1 item test_01.py::test_a 用户名 PASSED ================================================================================= 1 passed in 0.03 seconds =================================================================================
demo2:test_用例传多个fixture参数
# test_02.py import pytest @pytest.fixture() def username(): name = 'wangmm' return name @pytest.fixture() def pw(): password = '123456' return password def test_user(username, pw): assert username == 'wangmm' assert pw == '123456' 执行结果: D:myprojectpytest_demo estcases>pytest -vs test_02.py =================================================================================== test session starts ==================================================================================== platform win32 -- Python 3.6.5, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 -- d:softpython36python.exe cachedir: .pytest_cache rootdir: D:myprojectpytest_demo estcases collected 1 item test_02.py::test_user PASSED ================================================================================= 1 passed in 0.03 seconds ============================================= ====================================
demo3:fixture与fixture间相互调用
# test_03.py import pytest @pytest.fixture() def first(): a = "wangmm" return a @pytest.fixture() def sencond(first): '''psw调用user fixture''' a = first b = "123456" return (a, b) def test_1(sencond): '''用例传fixture''' assert sencond[0] == "wangmm" assert sencond[1] == "123456" 输出结果: D:myprojectpytest_demo estcases>pytest -vs test_03.py =================================================================================== test session starts ==================================================================================== platform win32 -- Python 3.6.5, pytest-5.0.1, py-1.8.0, pluggy-0.12.0 -- d:softpython36python.exe cachedir: .pytest_cache rootdir: D:myprojectpytest_demo estcases collected 1 item test_03.py::test_1 PASSED
2.使用usefixtures 但是需要注意如果fixture有返回值则不能使用usefixtures,usefixtures是获取不到返回值的
@pytest.mark.usefixtures("user") def test_b(): # u = user[0] # assert u == 'wangmm' assert 1 == 1
3.使用autos自动调用fixture 注意:如果不传autouse,默认scope=False
当然,如果需要用到fixture的返回结果,还是需要在入参中传入fixture
@pytest.fixture(scope='function',autouse=True) def login_test(): print("登录")
def test_s7(): # 该测试用例不需要传login_test,会自动调用的
print("用例1:登录之后其它动作111")
二 使用conftest.py实现多文件共享fixture
一个测试工程下是可以有多个conftest.py的文件,一般在工程根目录放一个conftest.py起到全局作用。
在不同的测试子目录也可以放conftest.py,作用范围只在该层级以及以下目录生效。
特别地:conftest.py不需要显示导入,pytest会自动读取该文件
session > module > class > function
@pytest.fixture(scope="session"):多个文件调用一次,可以跨.py,每个.py就是module
@pytest.fixture(scope="module"):module级别的fixture在当前.py模块里,只会在用例第一次调用前执行一次
@pytest.fixture(scope="class"):class级别的fixture,在每个类里,只会在第一次调用前执行一次
@pytest.fixture(scope="function"):function级别,每个函数都会调用(默认)
# conftest.py
import pytest
@pytest.fixture(scope="class")
def login():
print("登录系统")
# test_fix.py
import pytest
class Test1:
def test_s1(self,login):
print("用例1:登录之后其它动作111")
def test_s2(self): # 不传login
print("用例2:不需要登录,操作222")
def test_s3(self, login):
print("用例3:登录之后其它动作333")
class Test2:
def test_s4(self, login):
print("用例4:登录之后其它动作444")
def test_s5(self): # 不传login
print("用例5:不需要登录,操作555")
def test_s6(self, login):
print("用例6:登录之后其它动作666")
输出结果:
testcases est_fix.py 登录系统
用例1:登录之后其它动作111
.用例2:不需要登录,操作222
.用例3:登录之后其它动作333
.登录系统
用例4:登录之后其它动作444
.用例5:不需要登录,操作555
.用例6:登录之后其它动作666
三 fixture中yield的作用
Fixture finalization / executing teardown code
By using a yield statement instead of return, all the code after the yield statement serves as the teardown code.
测试代码的执行顺序: yield前的代码-测试用例中的代码-yield后的代码
demo1:
# conftest.py
import pytest
import smtplib
@pytest.fixture(scope='module')
def smtp_connection():
smtp_connection = smtplib.SMTP('smtp.126.com',25)
yield smtp_connection
print("teardown smtp")
smtp_connection.close()
# test_module.py
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
# assert 0
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
# assert 0
输出结果:
D:myprojectpytest_demo>pytest -qs --tb=no test_module.py # --tb=no,指关闭回溯信息
..teardown smtp
2 passed in 13.75 seconds
四 多个fixture的执行顺序
举例:
import pytest
order = []
@pytest.fixture(scope='session')
def s1():
order.append("s1")
@pytest.fixture(scope='module')
def m1():
order.append('m1')
@pytest.fixture()
def f1(f3):
order.append('f1')
@pytest.fixture()
def f3():
order.append('f3')
@pytest.fixture(autouse=True)
def a1():
order.append('a1')
@pytest.fixture()
def f2():
order.append('f2')
def test_order(f1, m1, f2, s1):
assert order == ["s1", "m1", "a1", "f3", "f1", "f2"]
输出结果:1 passed #即test_doder.py测试用例通过
理论:
session > module > class > function
@pytest.fixture(scope="session"):多个文件调用一次,可以跨.py,每个.py就是module
@pytest.fixture(scope="module"):module级别的fixture在当前.py模块里,只会在用例第一次调用前执行一次
@pytest.fixture(scope="class"):class级别的fixture,在每个类里,只会在第一次调用前执行一次
@pytest.fixture(scope="function"):function级别,每个函数都会调用(默认)
def fixture(scope="function", params=None, autouse=False, ids=None, name=None): :arg scope: the scope for which this fixture is shared, one of ``"function"`` (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``. ``"package"`` is considered **experimental** at this time.
特别地:平常写自动化用例会写一些前置的fixture操作,用例需要用到就直接传该函数的参数名称就行了。当用例很多的时候,每次都传这个参数,会比较麻烦。
fixture里面有个参数autouse,默认是Fasle没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了