pytest中的测试装置
<名称> | <作用范围> |
---|---|
setup_module/teardown_module | 全局模块级 |
setup_class/teardown_class | 类级,只在类中前后运行一次 |
setup_function/teardown_function | 函数级,每个函数前后运行一次 |
setup_method/teardown_method | 方法级,类中每个方法前后运行一次 |
setup/teardown | 方法级,类中每个方法前后运行一次 |
test_sample.py:
def setup_module():
print("\n模块级装置 setup_module")
def teardown_module():
print("\n模块级装置 teardown_module")
def setup_function():
print("\n函数级装置 setup_function")
def teardown_function():
print("\n函数级装置 teardown_function")
def test_f1():
print("执行测试函数-1")
def test_f2():
print("执行测试函数-2")
class TestSample(object):
def setup_class(self):
print("\n类级装置 setup_class")
def teardown_class(self):
print("\n类级装置 teardown_class")
def setup(self):
print("\n方法级装置 setup")
def teardown(self):
print("\n方法级装置 teardown")
def test_f1_cls(self):
print('执行测试方法-1')
def test_f2_cls(self):
print('执行测试方法-2')
执行用例:
pytest test_sample.py -vs
执行日志:
================================================================================ test session starts ================================================================================
platform win32 -- Python 3.8.10, pytest-5.4.2, py-1.11.0, pluggy-0.13.1 -- e:\workspace\rftestapi\venv\scripts\python.exe
cachedir: .pytest_cache
rootdir: E:\workspace\rftestapi\aitest\demo_pathlib2
plugins: repeat-0.8.0
collected 4 items
test_sample.py::test_f1
模块级装置 setup_module
函数级装置 setup_function
执行测试函数-1
PASSED
函数级装置 teardown_function
test_sample.py::test_f2
函数级装置 setup_function
执行测试函数-2
PASSED
函数级装置 teardown_function
test_sample.py::TestSample::test_f1_cls
类级装置 setup_class
方法级装置 setup
执行测试方法-1
PASSED
方法级装置 teardown
test_sample.py::TestSample::test_f2_cls
方法级装置 setup
执行测试方法-2
PASSED
方法级装置 teardown
类级装置 teardown_class
模块级装置 teardown_module
================================================================================= 4 passed in 0.12s =================================================================================
从结果可以看出用例执行顺序:
在函数上:
setup_module->setup_function->执行测试函数-1->teardown_function->teardown_module在类中:
setup_module->setup_class->setup->执行测试方法-1->teardown->teardown_class->teardown_module
fixture 装置
在fixtures中控制setup与teardown
** 通过addfinalizer注册teardown
test_sample.py:
import pytest
class TestSample(object):
@pytest.fixture()
def count(self,request):
print("\ninit count")
def fin():
print("\nteardown count")
request.addfinalizer(fin) # teardown
return 10 # provide the fixture value
def test_answer_1(self, count):
print('test_answer_1 get count: %s' % count)
assert count == 10
def test_answer_2(self, count):
print('test_answer_2 get count: %s' % count)
assert count == 10
** 通过yield呼唤teardown操作
test_sample.py:
import pytest
class TestSample(object):
@pytest.fixture()
def count(self):
print("\ninit count")
yield 10
print("\nteardown count")
def test_answer_1(self, count):
print('test_answer_1 get count: %s' % count)
assert count == 10
def test_answer_2(self, count):
print('test_answer_2 get count: %s' % count)
assert count == 10
执行用例:
pytest test_sample.py -vs
执行日志:
================================================================================ test session starts ================================================================================
platform win32 -- Python 3.8.10, pytest-5.4.2, py-1.11.0, pluggy-0.13.1 -- e:\workspace\rftestapi\venv\scripts\python.exe
cachedir: .pytest_cache
rootdir: E:\workspace\rftestapi\aitest\demo_pathlib2
plugins: repeat-0.8.0
collected 2 items
test_sample.py::TestSample::test_answer_1
init count
test_answer_1 get count: 10
PASSED
teardown count
test_sample.py::TestSample::test_answer_2
init count
test_answer_2 get count: 10
PASSED
teardown count
================================================================================= 2 passed in 0.08s =================================================================================
通过@pytest.fixture()注释会在执行测试用例之前初始化操作.然后直接在测试用例的方法中就可以拿到初始化返回的参数(参数名要和初始化的方法名一样)
在这个实例中,初始化的方法名为count,初始化后返回 10。当在测试用例方法中传入与初始化方法名同为count的参数时,相对于传入参数count=10
- 在fixture方法中, request.addfinalizer(),会将某函数作为teardown,在用例执行之后执行。
- 在fixture方法中, yield 会返回setup的值,yield之后的语句作为teardown执行。
fixture 的参数scope
fixture 有一个域(scope)的概念,用来指定该 fixture 的使用范围:session > module > class > function
它有五种作用域,如session/module/class/function(default).
- function:每个测试函数之前执行一次
- class:每个测试类之前执行一次
- module:每个module之前执行一次
- session:每次session之前执行一次,即每次测试执行一次
通过conftest.py共享fixture
如果一个fixture需要共享,不用在每个py模块中写一遍,写在conftest.py文件中就好。
conftest.py同级目录,或者其子目录中的模块,均可以直接引用conftest.py中使用@pytest.fixture装饰的函数,无需显式import
conftest.py
import pytest
@pytest.fixture(scope="session")
def count():
print("init count")
yield 10
print("teardown count")
test_sample.py:
class TestSample(object):
def test_answer_1(self, count):
print('test_answer_1 get count: %s' % count)
assert count == 10
def test_answer_2(self, count):
print('test_answer_2 get count: %s' % count)
assert count == 10
给fixture传参(params)
import pytest
@pytest.fixture(scope="module",params=["admin1","admin2"])
def login(request):
user = request.param
print("使用账户[%s]进行登录..." % user)
return user + "_logined"
def test_login(login):
'''登录用例'''
ret = login
print("login的返回值:%s" % ret)
assert "logined" in ret
或
import pytest
@pytest.fixture(scope="module")
def login(request):
user = request.param
print("使用账户[%s]进行登录..." % user)
return user + "_logined"
# indirect=True 声明login是个函数
@pytest.mark.parametrize("login", ["admin1", "admin2"], indirect=True)
def test_login(login):
'''登录用例'''
ret = login
print("login的返回值:%s" % ret)
assert "logined" in ret
添加indirect=True参数是为了把login当成一个函数去执行,而不是一个参数
执行用例:
pytest test_sample.py -vs
执行日志:
test_sample.py::test_login[admin1] 使用账户[admin1]进行登录...
login的返回值:admin1_logined
PASSED
test_sample.py::test_login[admin2] 使用账户[admin2]进行登录...
login的返回值:admin2_logined
PASSED
================================================================================= 2 passed in 0.06s =================================================================================
调用fixture的三种方法
- 函数或类里面方法直接传fixture的函数参数名称
- 使用装饰器@pytest.mark.usefixtures()修饰
- autouse=True自动使用
import pytest
@pytest.fixture(scope="session", params=["admin1", "admin2"])
def login_session(request):
user = request.param
print("使用账户[%s]进行登录..." % user)
return user + "_logined"
@pytest.fixture(scope="class", params=["admin3", "admin4"])
def login_cls(request):
user = request.param
print("使用账户[%s]进行登录..." % user)
return user + "_logined"
# autouse=True 会自动执行,不需要传入log参数
@pytest.fixture(scope="function", autouse=True)
def log(request):
print("开始执行用例:function:%s " % request.function.__name__)
# 用例传fixture参数,可获得fixture返回值
def test_login(login_session):
"""登录用例"""
ret = login_session
print("login的返回值:%s" % ret)
assert "logined" in ret
# usefixture 无法获取到fixture返回值
@pytest.mark.usefixtures("login_cls")
class TestCls:
def test_01(self):
print('-----------用例01--------------')
def test_02(self):
print('-----------用例02--------------')
执行结果 pytest -vs
collected 6 items
test_sample.py::test_login[admin1] 使用账户[admin1]进行登录...
开始执行用例:function:test_login
login的返回值:admin1_logined
PASSED
test_sample.py::test_login[admin2] 使用账户[admin2]进行登录...
开始执行用例:function:test_login
login的返回值:admin2_logined
PASSED
test_sample.py::TestCls::test_01[admin3] 使用账户[admin3]进行登录...
开始执行用例:function:test_01
-----------用例01--------------
PASSED
test_sample.py::TestCls::test_02[admin3] 开始执行用例:function:test_02
-----------用例02------------
PASSED
test_sample.py::TestCls::test_01[admin4] 使用账户[admin4]进行登录...
开始执行用例:function:test_01
-----------用例01--------------
PASSED
test_sample.py::TestCls::test_02[admin4] 开始执行用例:function:test_02
-----------用例02------------
PASSED
================================================================================= 6 passed in 0.19s =================================================================================
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。