Pytest + mock:补丁在没有 with 子句的情况下不起作用
Pytest + mock: patch does not work without with clause
我正在测试需要将中心事实 table 与 10-20 个更小维度的 table 结合起来的复杂逻辑。我想模拟 10-20 更小的 tables。
如何在 for 循环中修补方法 return 值? 请参阅下面的代码。
tables.py:
class BaseClass(object):
def load(path: str):
...
class SmallTable1(BaseClass):
def load():
super().load(self.path)
class SmallTable20(BaseClass):
def load():
super().load(self.path)
test_logic.py
# QUESTION - how to make it work
def test_not_work(datasets):
for i in range(1, 21):
table = 'SmallTable' + str(i)
with mock.patch('some_package.tables.{}.load'.format(table)) as load_mock:
load_mock.return_value = datasets[table]
do_joins() # here my mocks doesn't work
def test_works(datasets):
with mock.patch('some_package.tables.SmallTable1.load'.format(i)) as load_mock_1:
load_mock_1.return_value = datasets[SmallTable1]
with mock.patch('some_package.tables.SmallTable2.load'.format(i)) as load_mock_2:
load_mock_2.return_value = datasets[SmallTable2]
..... # repeat the same 8-18 times more
do_joins() # here my mocks do work, but with cumbersome code and huge right offset
P.S。或者我可以尝试模拟 BaseClass.load
,但我不知道如何 return 不同的数据集用于不同的 table (class).
假设 do_join
应在 循环外 调用,所有表都已修补,您可以编写一个使用 contextlib.ExitStack 来设置的固定装置所有模拟:
from contextlib import ExitStack
from unittest import mock
import pytest
from some_package import do_join
@pytest.fixture
def datasets():
...
@pytest.fixture
def mock_tables(datasets):
with ExitStack() as stack:
for i in range(1, 21):
table = 'SmallTable' + str(i)
load_mock = stack.enter_context(
mock.patch('some_package.tables.{}.load'.format(table)))
load_mock.return_value = datasets[table]
yield
def test_join(mock_tables):
do_join()
这意味着所有 mock 在 yield 时仍然处于活动状态,并且只有在测试完成后才会被删除。
如果您安装了 pytest-mock
,您可以改用 mocker
夹具:
@pytest.fixture
def mock_tables(datasets, mocker):
for i in range(1, 21):
table = 'SmallTable' + str(i)
load_mock = mocker.patch('some_package.tables.{}.load'.format(table))
load_mock.return_value = datasets[table]
yield
我正在测试需要将中心事实 table 与 10-20 个更小维度的 table 结合起来的复杂逻辑。我想模拟 10-20 更小的 tables。
如何在 for 循环中修补方法 return 值? 请参阅下面的代码。
tables.py:
class BaseClass(object):
def load(path: str):
...
class SmallTable1(BaseClass):
def load():
super().load(self.path)
class SmallTable20(BaseClass):
def load():
super().load(self.path)
test_logic.py
# QUESTION - how to make it work
def test_not_work(datasets):
for i in range(1, 21):
table = 'SmallTable' + str(i)
with mock.patch('some_package.tables.{}.load'.format(table)) as load_mock:
load_mock.return_value = datasets[table]
do_joins() # here my mocks doesn't work
def test_works(datasets):
with mock.patch('some_package.tables.SmallTable1.load'.format(i)) as load_mock_1:
load_mock_1.return_value = datasets[SmallTable1]
with mock.patch('some_package.tables.SmallTable2.load'.format(i)) as load_mock_2:
load_mock_2.return_value = datasets[SmallTable2]
..... # repeat the same 8-18 times more
do_joins() # here my mocks do work, but with cumbersome code and huge right offset
P.S。或者我可以尝试模拟 BaseClass.load
,但我不知道如何 return 不同的数据集用于不同的 table (class).
假设 do_join
应在 循环外 调用,所有表都已修补,您可以编写一个使用 contextlib.ExitStack 来设置的固定装置所有模拟:
from contextlib import ExitStack
from unittest import mock
import pytest
from some_package import do_join
@pytest.fixture
def datasets():
...
@pytest.fixture
def mock_tables(datasets):
with ExitStack() as stack:
for i in range(1, 21):
table = 'SmallTable' + str(i)
load_mock = stack.enter_context(
mock.patch('some_package.tables.{}.load'.format(table)))
load_mock.return_value = datasets[table]
yield
def test_join(mock_tables):
do_join()
这意味着所有 mock 在 yield 时仍然处于活动状态,并且只有在测试完成后才会被删除。
如果您安装了 pytest-mock
,您可以改用 mocker
夹具:
@pytest.fixture
def mock_tables(datasets, mocker):
for i in range(1, 21):
table = 'SmallTable' + str(i)
load_mock = mocker.patch('some_package.tables.{}.load'.format(table))
load_mock.return_value = datasets[table]
yield