pytest - 如果在方法内部调用了 class 的方法,如何断言
pytest - how to assert if a method of a class is called inside a method
我想知道如何知道 class 的方法是否在方法内部被调用。
单元测试代码如下:
# test_unittes.py file
def test_purge_s3_files(mocker):
args = Args()
mock_s3fs = mocker.patch('s3fs.S3FileSystem')
segment_obj = segments.Segmentation()
segment_obj.purge_s3_files('sample')
mock_s3fs.bulk_delete.assert_called()
在 purge_s3_file
方法中 bulk_delete
被调用,但是在断言时它说该方法应该被调用但没有被调用!
mocker = <pytest_mock.plugin.MockerFixture object at 0x7fac28d57208>
def test_purge_s3_files(mocker):
args = Args()
mock_s3fs = mocker.patch('s3fs.S3FileSystem')
segment_obj = segments.Segmentation(environment='qa',
verbose=True,
args=args)
segment_obj.purge_s3_files('sample')
> mock_s3fs.bulk_delete.assert_called()
E AssertionError: Expected 'bulk_delete' to have been called.
我不知道如何测试这个以及如果调用该方法如何断言!
您可以在下面找到正在测试的方法:
# segments.py file
import s3fs
def purge_s3_files(self, prefix=None):
bucket = 'sample_bucket'
files = []
fs = s3fs.S3FileSystem()
if fs.exists(f'{bucket}/{prefix}'):
files.extend(fs.ls(f'{bucket}/{prefix}'))
else:
print(f'Directory {bucket}/{prefix} does not exist in s3.')
print(f'Purging S3 files from {bucket}/{prefix}.')
print(*files, sep='\n')
fs.bulk_delete(files)
Python 模拟测试取决于模拟的使用位置。所以你在导入的地方模拟了函数调用。
例如
app/r_executor.py
def r_execute(file):
# do something
但实际的函数调用发生在另一个命名空间中 ->
analyse/news.py
from app.r_executor import r_execute
def analyse():
r_execute(file)
为了模拟这个我应该使用
mocker.patch('analyse.news.r_execute')
# not mocker.patch('app.r_executor.r_execute')
您面临的问题是您正在设置的模拟正在模拟 class,并且您没有使用 实例 来使用和检查您的嘲笑。简而言之,这个 应该 解决你的问题(下面可能有另一个问题进一步解释):
m = mocker.patch('s3fs.S3FileSystem')
mock_s3fs = m.return_value # (or mock_s3())
可能第二个问题是您没有引用正确的路径到您想要模拟的内容。
根据您的项目根目录(考虑您的评论 ),您的 mock 需要被相应地引用:
mock('app.segments.s3fs.S3FileSystem')
根据经验,您总是希望 mock where you are testing。
如果您能够使用调试器(或输出到您的控制台),您将(希望 :))看到您预期的调用计数将在模拟对象的 return_value
内。这是我的调试器使用您的代码的片段:
您会看到 call_count
属性设置为 1
。回到我在答案开头提到的内容,通过进行更改,您现在可以使用预期的 mock_s3fs.bulk_delete_assert_called()
.
将它们放在一起,经过修改的工作测试按预期运行(请注意,您还应该设置预期的行为并断言您在其中调用的其他 fs
方法):
def test_purge_s3_files(mocker):
m = mocker.patch("app.segments.s3fs.S3FileSystem")
mock_s3fs = m.return_value # (or m())
segment_obj = segments.Segmentation(environment='qa',
verbose=True,
args=args)
segment_obj.purge_s3_files('sample')
mock_s3fs.bulk_delete.assert_called()
我想知道如何知道 class 的方法是否在方法内部被调用。
单元测试代码如下:
# test_unittes.py file
def test_purge_s3_files(mocker):
args = Args()
mock_s3fs = mocker.patch('s3fs.S3FileSystem')
segment_obj = segments.Segmentation()
segment_obj.purge_s3_files('sample')
mock_s3fs.bulk_delete.assert_called()
在 purge_s3_file
方法中 bulk_delete
被调用,但是在断言时它说该方法应该被调用但没有被调用!
mocker = <pytest_mock.plugin.MockerFixture object at 0x7fac28d57208>
def test_purge_s3_files(mocker):
args = Args()
mock_s3fs = mocker.patch('s3fs.S3FileSystem')
segment_obj = segments.Segmentation(environment='qa',
verbose=True,
args=args)
segment_obj.purge_s3_files('sample')
> mock_s3fs.bulk_delete.assert_called()
E AssertionError: Expected 'bulk_delete' to have been called.
我不知道如何测试这个以及如果调用该方法如何断言!
您可以在下面找到正在测试的方法:
# segments.py file
import s3fs
def purge_s3_files(self, prefix=None):
bucket = 'sample_bucket'
files = []
fs = s3fs.S3FileSystem()
if fs.exists(f'{bucket}/{prefix}'):
files.extend(fs.ls(f'{bucket}/{prefix}'))
else:
print(f'Directory {bucket}/{prefix} does not exist in s3.')
print(f'Purging S3 files from {bucket}/{prefix}.')
print(*files, sep='\n')
fs.bulk_delete(files)
Python 模拟测试取决于模拟的使用位置。所以你在导入的地方模拟了函数调用。
例如
app/r_executor.py
def r_execute(file):
# do something
但实际的函数调用发生在另一个命名空间中 ->
analyse/news.py
from app.r_executor import r_execute
def analyse():
r_execute(file)
为了模拟这个我应该使用
mocker.patch('analyse.news.r_execute')
# not mocker.patch('app.r_executor.r_execute')
您面临的问题是您正在设置的模拟正在模拟 class,并且您没有使用 实例 来使用和检查您的嘲笑。简而言之,这个 应该 解决你的问题(下面可能有另一个问题进一步解释):
m = mocker.patch('s3fs.S3FileSystem')
mock_s3fs = m.return_value # (or mock_s3())
可能第二个问题是您没有引用正确的路径到您想要模拟的内容。
根据您的项目根目录(考虑您的评论
mock('app.segments.s3fs.S3FileSystem')
根据经验,您总是希望 mock where you are testing。
如果您能够使用调试器(或输出到您的控制台),您将(希望 :))看到您预期的调用计数将在模拟对象的 return_value
内。这是我的调试器使用您的代码的片段:
您会看到 call_count
属性设置为 1
。回到我在答案开头提到的内容,通过进行更改,您现在可以使用预期的 mock_s3fs.bulk_delete_assert_called()
.
将它们放在一起,经过修改的工作测试按预期运行(请注意,您还应该设置预期的行为并断言您在其中调用的其他 fs
方法):
def test_purge_s3_files(mocker):
m = mocker.patch("app.segments.s3fs.S3FileSystem")
mock_s3fs = m.return_value # (or m())
segment_obj = segments.Segmentation(environment='qa',
verbose=True,
args=args)
segment_obj.purge_s3_files('sample')
mock_s3fs.bulk_delete.assert_called()