mocker.patch 使用先前参数化的数据 运行
mocker.patch uses data from the previous parametrized run
我是 pytest 的新手,所以我可能会错误地使用一些 pytest 语义。
总的来说,我遇到了以下问题:
我在测试中使用 mark.parametrize 进行模拟,当我在参数中使用相同的变量时,模拟使用的是前一个 运行 的数据,而不是我指定的数据.
解析:
在第一个 'iteration' 中,在 mark.parametrize 中我使用 mock_data_1 来模拟 GetData.get_data()。然后,测试如我所料在此处模拟 data
:data = GetData.get_data()
然后它向数据 data['new_col0']
.
添加一个新列
在第二个 'iteration',在 mark.parametrize 我再次使用 mock_data_1,而不是使用一组新的mock_data_1,测试使用以前的数据,包含额外的列。
这些是一些示例文件:
file.py
from test_file_get_data import GetData
class MyClass:
def new_dataset(arg):
data = GetData.get_data(arg) # Mock this part
data[f'new_col{arg}'] = arg # New column to data
return data
test_file.py
from file import MyClass
import pandas as pd
import pytest
class TestMyClass:
mock_data_1 = pd.DataFrame({"col_1": [1,2,3]})
arg_1 = 0
arg_2 = 1
output_1 = pd.DataFrame({"col_1": [1,2,3], "new_col0": [0,0,0]})
output_2 = pd.DataFrame({"col_1": [1,2,3], "new_col1": [1,1,1]})
@pytest.mark.parametrize(
'mock_arguments, arg, result',
[
(mock_data_1, arg_1, output_1),
(mock_data_1, arg_2, output_2)
]
)
def test_new_dataset(self, mocker, mock_arguments, arg, result):
mocker.patch(
'file.GetData.get_data',
return_value=mock_arguments,
)
print(mock_arguments)
res = MyClass.new_dataset(arg)
print(res)
assert res.to_dict() == result.to_dict()
test_file_get_data.py
import pandas as pd
class GetData:
def get_data(arg):
data = pd.DataFrame({"a":[1, 2, 3]})
return data
所以第一个测试通过了,但是第二个失败了,因为返回的数据是这样的:
{'col_1': {1, 2, 3},
'new_col0': {0, 0, 0},
'new_col1': {1, 1, 1}}
而不是这个:
{'col_1': {1, 2, 3},
'new_col1': {1, 1, 1}}
如果我用 data = GetData.get_data().copy()
替换 data = GetData.get_data()
可以解决这个问题,但我假设我在测试中做错了。
数据不是应该在每次迭代后刷新and/or删除吗?
或者正在发生的是预期的行为?
如评论中所述,问题是在测试中使用了全局变量(在本例中为 class 变量,但不会改变行为),在测试内部发生了变化,并且然后在下一个测试中使用更改的变量。没有任何内容告诉 pytest
变量应该被重置 - 重置变量通常在 fixtures 中完成。
如果像在您的示例中一样,参数在测试中没有更改,则您根本不必将其添加为参数。在这种情况下,您可以使用在每次测试中重置的固定装置:
class TestMyClass:
arg_1 = 0
arg_2 = 1
output_1 = pd.DataFrame({"col_1": [1, 2, 3], "new_col0": [0, 0, 0]})
output_2 = pd.DataFrame({"col_1": [1, 2, 3], "new_col1": [1, 1, 1]})
@pytest.fixture
def mock_arguments(self):
return pd.DataFrame({"col_1": [1, 2, 3]})
@pytest.mark.parametrize(
'arg, result',
[
(arg_1, output_1),
(arg_2, output_2)
]
)
def test_new_dataset(self, mocker, mock_arguments, arg, result):
mocker.patch(
'file.GetData.get_data',
return_value=mock_arguments,
)
print(mock_arguments)
...
这是 pytest
中处理变量重置的标准方法。
如果你想像你一样使用parametrize
中的参数(例如因为参数不是对所有测试都相同),你不能使用夹具,因为装饰器已经在加载时读取时间。在这种情况下
您必须首先自己确保原始参数被重置或未更改,例如像您一样使用副本 - 但在测试而不是生产代码中,您不想更改它:
@pytest.mark.parametrize(
'mock_arguments, arg, result',
[
(mock_data_1, arg_1, output_1),
(mock_data_1, arg_2, output_2)
]
)
def test_new_dataset(self, mocker, mock_arguments, arg, result):
mocker.patch(
'file.GetData.get_data',
return_value=mock_arguments.copy(), # use a copy of the value
)
print(mock_arguments)
...
在 re-reading pytest 文档之后,我发现他们明确指出这是测试的预期行为:
Note:
Parameter values are passed as-is to tests (no copy whatsoever).
For example, if you pass a list or a dict as a parameter value, and
the test case code mutates it, the mutations will be reflected in
subsequent test case calls.
我是 pytest 的新手,所以我可能会错误地使用一些 pytest 语义。
总的来说,我遇到了以下问题:
我在测试中使用 mark.parametrize 进行模拟,当我在参数中使用相同的变量时,模拟使用的是前一个 运行 的数据,而不是我指定的数据.
解析:
在第一个 'iteration' 中,在 mark.parametrize 中我使用 mock_data_1 来模拟 GetData.get_data()。然后,测试如我所料在此处模拟 data
:data = GetData.get_data()
然后它向数据 data['new_col0']
.
在第二个 'iteration',在 mark.parametrize 我再次使用 mock_data_1,而不是使用一组新的mock_data_1,测试使用以前的数据,包含额外的列。
这些是一些示例文件:
file.py
from test_file_get_data import GetData
class MyClass:
def new_dataset(arg):
data = GetData.get_data(arg) # Mock this part
data[f'new_col{arg}'] = arg # New column to data
return data
test_file.py
from file import MyClass
import pandas as pd
import pytest
class TestMyClass:
mock_data_1 = pd.DataFrame({"col_1": [1,2,3]})
arg_1 = 0
arg_2 = 1
output_1 = pd.DataFrame({"col_1": [1,2,3], "new_col0": [0,0,0]})
output_2 = pd.DataFrame({"col_1": [1,2,3], "new_col1": [1,1,1]})
@pytest.mark.parametrize(
'mock_arguments, arg, result',
[
(mock_data_1, arg_1, output_1),
(mock_data_1, arg_2, output_2)
]
)
def test_new_dataset(self, mocker, mock_arguments, arg, result):
mocker.patch(
'file.GetData.get_data',
return_value=mock_arguments,
)
print(mock_arguments)
res = MyClass.new_dataset(arg)
print(res)
assert res.to_dict() == result.to_dict()
test_file_get_data.py
import pandas as pd
class GetData:
def get_data(arg):
data = pd.DataFrame({"a":[1, 2, 3]})
return data
所以第一个测试通过了,但是第二个失败了,因为返回的数据是这样的:
{'col_1': {1, 2, 3},
'new_col0': {0, 0, 0},
'new_col1': {1, 1, 1}}
而不是这个:
{'col_1': {1, 2, 3},
'new_col1': {1, 1, 1}}
如果我用 data = GetData.get_data().copy()
替换 data = GetData.get_data()
可以解决这个问题,但我假设我在测试中做错了。
数据不是应该在每次迭代后刷新and/or删除吗? 或者正在发生的是预期的行为?
如评论中所述,问题是在测试中使用了全局变量(在本例中为 class 变量,但不会改变行为),在测试内部发生了变化,并且然后在下一个测试中使用更改的变量。没有任何内容告诉 pytest
变量应该被重置 - 重置变量通常在 fixtures 中完成。
如果像在您的示例中一样,参数在测试中没有更改,则您根本不必将其添加为参数。在这种情况下,您可以使用在每次测试中重置的固定装置:
class TestMyClass:
arg_1 = 0
arg_2 = 1
output_1 = pd.DataFrame({"col_1": [1, 2, 3], "new_col0": [0, 0, 0]})
output_2 = pd.DataFrame({"col_1": [1, 2, 3], "new_col1": [1, 1, 1]})
@pytest.fixture
def mock_arguments(self):
return pd.DataFrame({"col_1": [1, 2, 3]})
@pytest.mark.parametrize(
'arg, result',
[
(arg_1, output_1),
(arg_2, output_2)
]
)
def test_new_dataset(self, mocker, mock_arguments, arg, result):
mocker.patch(
'file.GetData.get_data',
return_value=mock_arguments,
)
print(mock_arguments)
...
这是 pytest
中处理变量重置的标准方法。
如果你想像你一样使用parametrize
中的参数(例如因为参数不是对所有测试都相同),你不能使用夹具,因为装饰器已经在加载时读取时间。在这种情况下
您必须首先自己确保原始参数被重置或未更改,例如像您一样使用副本 - 但在测试而不是生产代码中,您不想更改它:
@pytest.mark.parametrize(
'mock_arguments, arg, result',
[
(mock_data_1, arg_1, output_1),
(mock_data_1, arg_2, output_2)
]
)
def test_new_dataset(self, mocker, mock_arguments, arg, result):
mocker.patch(
'file.GetData.get_data',
return_value=mock_arguments.copy(), # use a copy of the value
)
print(mock_arguments)
...
在 re-reading pytest 文档之后,我发现他们明确指出这是测试的预期行为:
Note:
Parameter values are passed as-is to tests (no copy whatsoever).
For example, if you pass a list or a dict as a parameter value, and the test case code mutates it, the mutations will be reflected in subsequent test case calls.