python 在单元测试中打补丁不起作用,正在调用实际方法

0mkxixxg  于 2023-03-21  发布在  Python
关注(0)|答案(2)|浏览(137)

我有一个python文件:update_baseline_manifest. py。现在,我正在编写单元测试,并希望修补read_file和write_file,我已经这样做了

def update_baseline_manifest(baseline_manifest_path, vbf_info_map, logger):
    """ Updates manifest as per the part numbers in the vbfs_map """
    try:
        manifest_contents = read_file(baseline_manifest_path)
        // Do something

        write_file(manifest_contents, baseline_manifest_path)

def read_file(file_path):
    print('called read')
    with open(file_path, 'r') as file:
        return yaml.safe_load(file)

def write_file(contents, file_path):
    print('called write')
    with open(file_path, 'w') as file:
        yaml.dump(contents, file)

测试文件如下所示

from a.b.update_baseline_manifest import update_baseline_manifest

def test_update_baseline_manifest(self):
    test_contents = 'sample contents'

    with patch('update_baseline_manifest.read_file', return_value=test_contents) as \
        mock_read, patch('update_baseline_manifest.write_file') as mock_write:
        result = update_baseline_manifest(self.args.baseline_manifest_path,
                                            self.args.vbf_info_map,
                                            self.args.logger)

    mock_read.assert_called_with(self.args.baseline_manifest_path)
    mock_write.assert_called_with(contents_written, self.args.baseline_manifest_path)
    self.assertEqual(result, 0)

现在我可以看到我添加的打印,所以这意味着实际的函数被调用,而模拟的函数没有。我如何正确地修补它们,以便在导入顶部的文件后调用我的模拟函数,而不是实际的函数?我读了很多关于它的帖子,但我无法理解它。

50few1ms

50few1ms1#

您需要提供要模拟的函数的完整路径。请参阅:https://docs.python.org/3/library/unittest.mock.html#where-to-patch

...
    with patch('a.b.update_baseline_manifest.read_file', return_value=test_contents) as \
mock_read, patch('a.b.update_baseline_manifest.write_file') as mock_write:
    ...
yqlxgs2m

yqlxgs2m2#

我已经在我的系统中测试了你的代码,正如@Gameplay所说,唯一的问题是你在patch()指令中使用的模块的路径。

最重要的修改

我变了:

# YOUR
with patch('update_baseline_manifest.read_file', return_value=test_contents) as mock_read, \
     patch('update_baseline_manifest.write_file') as mock_write:

#+++++++++++++++++++++++++++++++++++++++++++++++++++++++
# TO MINE: I have added the path of the file
# update_baseline_manifest.py in the patch() instruction
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++
with patch('a.b.update_baseline_manifest.read_file', return_value=test_contents) as mock_read, \
     patch('a.b.update_baseline_manifest.write_file') as mock_write:

答案的其余部分详细说明了用于在我的系统中复制测试的代码。

您的生产代码在我的系统中

我重新创建了脚本update_baseline_manifest.py,如下所示:

def update_baseline_manifest(baseline_manifest_path, vbf_info_map, logger):
    """ Updates manifest as per the part numbers in the vbfs_map """
    try:
        manifest_contents = read_file(baseline_manifest_path)
        # Do something
        write_file(manifest_contents, baseline_manifest_path)
        return 0
    except Exception as ex:
        print(str(ex))

def read_file(file_path):
    print('called read')
    with open(file_path, 'r') as file:
        return yaml.safe_load(file)

def write_file(contents, file_path):
    print('called write')
    with open(file_path, 'w') as file:
        yaml.dump(contents, file)

我只在函数update_baseline_manifest中添加了一些指令:

  • return 0通过您的测试self.assertEqual(result, 0)
  • except Exception as ex:完成try:指令

文件保存在路径a/b/update_baseline_manifest.py中,其中ab包含文件__init__.py

您在我系统中的测试代码

我的测试代码如下:

import unittest
from unittest.mock import patch
from a.b.update_baseline_manifest import update_baseline_manifest

# utility class for not change your test code
class ARGS:
    baseline_manifest_path = "/path/to/manifest"
    vbf_info_map = "vbf info map"
    logger = "logger"

class MyTestCase(unittest.TestCase):

    args = ARGS()

    def test_update_baseline_manifest(self):
        test_contents = 'sample contents'
        with patch('a.b.update_baseline_manifest.read_file', return_value=test_contents) as mock_read \
             patch('a.b.update_baseline_manifest.write_file') as mock_write:
            result = update_baseline_manifest(self.args.baseline_manifest_path,
                                                self.args.vbf_info_map,
                                                self.args.logger)

        mock_read.assert_called_with(self.args.baseline_manifest_path)
        #mock_write.assert_called_with(contents_written, self.args.baseline_manifest_path)
        mock_write.assert_called_with(test_contents, self.args.baseline_manifest_path)
        self.assertEqual(result, 0)

if __name__ == '__main__':
    unittest.main()

在测试文件中,我添加了以下import

import unittest
from unittest.mock import patch

我还添加了(utilityclass ARGS来定义MyTestCase的属性arg

class ARGS:
    baseline_manifest_path = "/path/to/manifest"
    vbf_info_map = "vbf info map"
    logger = "logger"

我修改了一个测试如下:

# your test
#mock_write.assert_called_with(contents_written, self.args.baseline_manifest_path)

# my test
mock_write.assert_called_with(test_contents, self.args.baseline_manifest_path)

最后,但最重要的修改(正如我在答案的顶部所写的):

我已经更改了patch指令中的路径。

输出

执行的输出是:

.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

在输出中不存在任何打印的消息,因此我们可以确定未调用生产代码!

相关问题