如何将数据传递给pytest中的monkeypatch
How to pass data to a monkeypatch in pytest
我有一个简单的测试,我想测试用户数据的正确创建。
Data
的创建取决于用户的周数(可以认为是加入的一周)。这意味着具有 week=2
的用户应该拥有所有 Data
个对象,这些对象也具有 week=2
。由于我有不同周的用户,我希望我的测试涵盖几个星期。我的问题是 User.week
是一个 属性,它使用计算来获得真实的周数,我不知道如何将 week
参数传递给我的 monkeypatch fixture 以生成静态值是“动态的”。
现在我有了一个适合我的丑陋解决方案 - 我创建了两个具有不同 return 值的相同模拟。
test_tasks.py
from users.tasks import create_default_data_for_user
class TestUserTasks:
@pytest.mark.parametrize(
"week",
["mock_user_week_1", "mock_user_week_2"]
)
def test_create_default_data_for_user(self, user, rf, data, week):
"""
Check creation of user data using create_default_data_for_user task.
:param user: a user object fixture
:param rf: instance of Django test RequestFactory
:param data: fixture that creates default data object
:param week: mock object of user's week property
:return:
"""
# Make sure the user has no user data
assert len(user.data_set.all()) == 0
create_default_data_for_user()
# Now the user should be given data according to his week
expected_user_data_count = Data.objects.filter(week=user.week).count()
assert len(user.data_set.all()) == expected_user_data_count
# Make sure that for the current user the second run will not cause user data duplication
create_default_data_for_user()
assert len(user.data_set.all()) == expected_user_data_count
fixtures.py
import pytest
@pytest.fixture
def mock_user_week_1(monkeypatch):
"""
Mock the User object's property week.
The mock object will prevent calculation of the real User's week
and just return a given number.
"""
@property
def user_week(*args, **kwargs):
"""
A mock object that overrides the method and returns a static value.
:param args: args of the original object
:param kwargs: kwargs of the original object
:return: static value indicating week number 1
"""
return 1
monkeypatch.setattr(
User,
"week",
user_week
)
@pytest.fixture
def mock_user_week_2(monkeypatch):
"""
Mock the User object's property week.
The mock object will prevent calculation of the real User's week
and just return a given number.
"""
# pylint: disable=unused-argument
@property
def user_week(*args, **kwargs):
"""
A mock object that overrides the method and returns a static value.
:param args: args of the original object
:param kwargs: kwargs of the original object
:return: static value indicating week number 2
"""
return 2
monkeypatch.setattr(
User,
"week",
user_week
)
终于,我明白了。
结果证明解决方案很简单:
fixtures.py
@pytest.fixture
def mock_user_week(monkeypatch, week_number):
"""
Mock the User object's method week.
The mock object will prevent calculation of the real User's week
and just return a given number.
"""
@property
def user_week(*args, **kwargs):
"""
A mock object that overrides the method and return static value.
:param args: args of the original object
:param kwargs: kwargs of the original object
:return: static value indicating week number
"""
return week_number
monkeypatch.setattr(
User,
"week_in_program",
user_week_in_program
)
test_tasks.py
from users.tasks import create_default_data_for_user
class TestUserTasks:
@pytest.mark.parametrize(
"week_number",
[1, 2, 3, 4, 5]
)
def test_create_default_data_for_user(self, user, rf, data, week_number, mock_user_week):
"""
Check creation of user data using create_default_data_for_user task.
:param user: a user object fixture
:param rf: instance of Django test RequestFactory
:param data: fixture that creates default data object
:param int week_number: user's week to be used
:param mock_user_week: mock object of user's week property
:return:
"""
# Make sure the user has no user data
assert len(user.data_set.all()) == 0
create_default_data_for_user()
# Now the user should be given data according to his week
expected_user_data_count = Data.objects.filter(week=user.week).count()
assert len(user.data_set.all()) == expected_user_data_count
# Make sure that for the current user the second run will not cause user data duplication
create_default_data_for_user()
assert len(user.data_set.all()) == expected_user_data_count
这里的“魔法”是我在参数化、测试方法参数和模拟夹具中使用参数 week_number
。因此 pytest 将此参数传递给测试方法和模拟夹具。在这种特殊情况下,每个 parametrize
运行 都会从模拟夹具中产生一个新的 return 值。在测试中,我正在为给定列表的不同周创建 Data
个对象。
我什至无法认为 pytest 本身将参数传递给固定装置而无需额外的“设置”。
如果文档中有这样的东西就好了。
我有一个简单的测试,我想测试用户数据的正确创建。
Data
的创建取决于用户的周数(可以认为是加入的一周)。这意味着具有 week=2
的用户应该拥有所有 Data
个对象,这些对象也具有 week=2
。由于我有不同周的用户,我希望我的测试涵盖几个星期。我的问题是 User.week
是一个 属性,它使用计算来获得真实的周数,我不知道如何将 week
参数传递给我的 monkeypatch fixture 以生成静态值是“动态的”。
现在我有了一个适合我的丑陋解决方案 - 我创建了两个具有不同 return 值的相同模拟。
test_tasks.py
from users.tasks import create_default_data_for_user
class TestUserTasks:
@pytest.mark.parametrize(
"week",
["mock_user_week_1", "mock_user_week_2"]
)
def test_create_default_data_for_user(self, user, rf, data, week):
"""
Check creation of user data using create_default_data_for_user task.
:param user: a user object fixture
:param rf: instance of Django test RequestFactory
:param data: fixture that creates default data object
:param week: mock object of user's week property
:return:
"""
# Make sure the user has no user data
assert len(user.data_set.all()) == 0
create_default_data_for_user()
# Now the user should be given data according to his week
expected_user_data_count = Data.objects.filter(week=user.week).count()
assert len(user.data_set.all()) == expected_user_data_count
# Make sure that for the current user the second run will not cause user data duplication
create_default_data_for_user()
assert len(user.data_set.all()) == expected_user_data_count
fixtures.py
import pytest
@pytest.fixture
def mock_user_week_1(monkeypatch):
"""
Mock the User object's property week.
The mock object will prevent calculation of the real User's week
and just return a given number.
"""
@property
def user_week(*args, **kwargs):
"""
A mock object that overrides the method and returns a static value.
:param args: args of the original object
:param kwargs: kwargs of the original object
:return: static value indicating week number 1
"""
return 1
monkeypatch.setattr(
User,
"week",
user_week
)
@pytest.fixture
def mock_user_week_2(monkeypatch):
"""
Mock the User object's property week.
The mock object will prevent calculation of the real User's week
and just return a given number.
"""
# pylint: disable=unused-argument
@property
def user_week(*args, **kwargs):
"""
A mock object that overrides the method and returns a static value.
:param args: args of the original object
:param kwargs: kwargs of the original object
:return: static value indicating week number 2
"""
return 2
monkeypatch.setattr(
User,
"week",
user_week
)
终于,我明白了。 结果证明解决方案很简单:
fixtures.py
@pytest.fixture
def mock_user_week(monkeypatch, week_number):
"""
Mock the User object's method week.
The mock object will prevent calculation of the real User's week
and just return a given number.
"""
@property
def user_week(*args, **kwargs):
"""
A mock object that overrides the method and return static value.
:param args: args of the original object
:param kwargs: kwargs of the original object
:return: static value indicating week number
"""
return week_number
monkeypatch.setattr(
User,
"week_in_program",
user_week_in_program
)
test_tasks.py
from users.tasks import create_default_data_for_user
class TestUserTasks:
@pytest.mark.parametrize(
"week_number",
[1, 2, 3, 4, 5]
)
def test_create_default_data_for_user(self, user, rf, data, week_number, mock_user_week):
"""
Check creation of user data using create_default_data_for_user task.
:param user: a user object fixture
:param rf: instance of Django test RequestFactory
:param data: fixture that creates default data object
:param int week_number: user's week to be used
:param mock_user_week: mock object of user's week property
:return:
"""
# Make sure the user has no user data
assert len(user.data_set.all()) == 0
create_default_data_for_user()
# Now the user should be given data according to his week
expected_user_data_count = Data.objects.filter(week=user.week).count()
assert len(user.data_set.all()) == expected_user_data_count
# Make sure that for the current user the second run will not cause user data duplication
create_default_data_for_user()
assert len(user.data_set.all()) == expected_user_data_count
这里的“魔法”是我在参数化、测试方法参数和模拟夹具中使用参数 week_number
。因此 pytest 将此参数传递给测试方法和模拟夹具。在这种特殊情况下,每个 parametrize
运行 都会从模拟夹具中产生一个新的 return 值。在测试中,我正在为给定列表的不同周创建 Data
个对象。
我什至无法认为 pytest 本身将参数传递给固定装置而无需额外的“设置”。
如果文档中有这样的东西就好了。