pytest之fixture简介
上一篇 /
下一篇 2021-05-10 16:30:53
/ 个人分类:单元测试
fixture介绍
fixture是在
测试函数运行前后,由pytest执行的外壳函数。fixture中的代码可以定制,满足多变的测试需求,包括定义传入测试中的数据集、配置测试前系统的初始状态、为批量测试提供数据源,等等。
import pytest
@pytest.fixture() def some_data(): return 42
def test_some_data(some_data): assert some_data == 42 |
@pytest.fixture()装饰器用于声明函数是一个fixture。如果测试函数的参数列表中包含fixture名,那么pytest会检测到,并在测试函数运行之前执行该fixture。fixture可以完成任务,也可以返回数据给测试函数。
通过conftest.py共享fixture
如果你希望多个测试文件共享fixture,可以在某个公共目录下新建一个conftest.py文件,将fixture放在其中。conftest.py被pytest视作一个本地插件库。可以把tests/conftest.py看成是一个供tests目录下所有测试使用的fixture仓库。
使用fixture执行配置及销毁逻辑:
import pytest import tasks from tasks import Task
@pytest.fixture() def tasks_db(tmpdir): """connect to db defore tests, disconnect after.""" # Setup : start db tasks.start_tasks_db(str(tmpdir), 'tiny') yield # this is where the testing happens # Teardown : stop db tasks.stop_tasks_db() |
fixture函数会在测试函数之前运行,但如果fixture函数包含yield,那么系统会在yield处停止,转而运行测试函数,等测试函数执行完毕后再回到fixture,继续执行yield后面的代码。因此,可以将yield之前的代码视为配置(setup)过程,将yield之后的代码视为清理(teardown)过程。无论测试过程中发生了什么,yield之后的代码都会被执行。
使用--setup-show回溯fixture的执行过程
使用--setup-show选项可以看到测试过程中执行的是什么,以及执行的先后顺序。 fixture名称前面的F和S代表的是fixture的作用范围,F代表函数级别的作用范围,S代表会话级别的作用范围。
(ly_venv) liuyan@Lydemacpro func % pytest --setup-show test_add.py -k valid_id ============================= test session starts ============================== platform darwin -- Python 3.6.4, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 rootdir: /Users/liuyan/PycharmProjects/code/ch3/a/tasks_proj/tests, configfile: pytest.ini plugins: allure-pytest-2.8.34, html-3.1.1, metadata-1.11.0 collected 3 items / 2 deselected / 1 selected
test_add.py SETUP S tmp_path_factory SETUP F tmp_path (fixtures used: tmp_path_factory) SETUP F tmpdir (fixtures used: tmp_path) SETUP F tasks_db (fixtures used: tmpdir) func/test_add.py::test_add_returns_valid_id (fixtures used: request, tasks_db, tmp_path, tmp_path_factory, tmpdir). TEARDOWN F tasks_db TEARDOWN F tmpdir TEARDOWN F tmp_path TEARDOWN S tmp_path_factory |
使用fixture传递测试数据
fixture非常适合存放测试数据,并且它可以返回任何数据。
import pytest
@pytest.fixture() def a_tuple(): """Return something more interesting.""" return (1, 'foo', None, {'bar': 23})
def test_a_tuple(a_tuple): """Demo the a_tuple fixture.""" assert a_tuple[3]['bar'] == 32 |
假设assert异常(或任何类型的异常)就发生在fixture,则报告会用ERROR而不是FAIL。如果测试结果为FAIL,用户就知道失败是发生在核心测试函数内,而不是发生在测试依赖的fixture。可以使用多个fixture。
使用fixture的优势在于:用户在编写测试函数时可以只考虑核心测试逻辑,而不需要考虑测试前的准备工作。
指定fixture作用范围
fixture包含一个叫scope(作用范围)的可选参数,用于控制fixture执行配置和销毁逻辑的频率。@pytest.fixture()的scope参数有四个待选值:function、class、module、session(默认为function)。
scope='function':函数级别的fixture每个测试函数只需要运行一次。配置代码在
测试用例运行之前运行,销毁代码在测试用例运行之后运行。
scope='class':类级别的fixture每个测试类只需要运行一次。无论测试类里有多少类方法都可以共享这个fixture。
scope='module':模块级别的fixture每个模块只需要运行一次。无论模块里有多少类方法都可以共享这个fixture。
scope='session':会话级别的fixture每个会话只需要运行一次。一次pytest会话中的所有测试函数、方法都可以共享这个fixture。
使用usefixtures指定fixture
可以用@pytest.mark.usefixtures('fixture1','fixture2')标记测试函数或类。使用usefixtures,需要在参数列表中指定一个或多个fixture字符串。这对测试函数来讲意义不大,但非常适合测试类。
@pytest.mark.usefixtures('class_scope') class TestSomething(): """Demo class scope fixtures."""
def test_3(self): """Test using a class scope fixture."""
def test_4(self): """Again, multiple tests are more fun.""" |
使用usefixtures和在测试方法中添加fixture参数,二者大体上是差不多的。区别之一在于只有后者才能够使用fixture的返回值。
为fixture重命名
pytest允许使用@pytest.fixture()的name参数对fixture重命名。
import pytest
@pytest.fixture(name='lue') def ultimate_answer_to_life_the_universe_and_everything(): """Return ultimate answer.""" return 42
def test_everything(lue): """Use the shorter name.""" assert lue == 42 |
收藏
举报
TAG: