【问题标题】:Python mocking not working for shutil.rmtreePython 模拟不适用于 shutil.rmtree
【发布时间】:2018-03-20 07:24:45
【问题描述】:

我有一个类,其方法使用 shutil.rmtree 如果参数被传递为 true 来删除一些文件,如何模拟这种行为,以便其他需要这些文件的测试不会中断。

我的班级看起来像这样 -

class FileConverter(object):

    def __init__(self, path_to_files):
        self._path_to_files = path_to_files

    def convert_files(self, rmv_src=False):
        doStuff()
        if rmv_src:
            shutil.rmtree(self.__path_to_files)

    def doStuff():
        # does some stuff

现在我的测试看起来像 -

class TestFileConverter(unittest.TestCase):

    def test_convert_success(self):
        input_dir = 'resources/files'
        file_converter = FileConverter(input_dir)
        file_converter.convert_files()

        # assert the things from doStuff

    @mock.patch('shutil.rmtree')
    def test_convert_with_rmv(self, rm_mock):
        input_dir = 'resources/files'
        file_converter = FileConverter(input_dir)
        file_converter.convert_files(True)

        self.assertEquals(rm_mock, [call(input_dir)])

现在当我运行这个测试套件时,使用 rmv 的测试给了我 assertionError

<MagicMock name='rmtree' id='139676276822984'> != [call('resources/images')]

第一个测试给了我文件未找到错误,因为模拟不起作用并且 rmv 源测试删除了文件

FileNotFoundError: [Errno 2] No such file or directory: 'resources/images'

如果我用 rmv_source true 注释掉第二个测试,那么我的第一个测试工作正常。 我在这里做错了什么?

【问题讨论】:

    标签: python unit-testing testing mocking


    【解决方案1】:

    您的模块已经导入 shutil.rmtree,因此稍后在测试套件中模拟它不会有任何作用。

    您需要在导入 FileConverter 时模拟模块,而不是之后。

    import sys
    from mock import MagicMock
    
    sys.modules['shutil'] = MagicMock()
    # and/or
    sys.modules['shutil.rmtree'] = MagicMock()
    import FileConverter
    

    如果你仍然需要在你的测试代码中使用shutil,那么首先使用别名导入它,并在你需要“真正的”模块时使用它:

    import sys
    from mock import MagicMock
    
    import shutil as shutil_orig
    sys.modules['shutil'] = MagicMock()
    import shutil
    
    print(type(shutil_orig.rmtree))
    # <class 'function'>
    print(type(shutil.rmtree))
    # <class 'mock.mock.MagicMock'>
    

    【讨论】:

    • 我在第一个测试中也使用了 shutil.rmtree 来清理 doStuff 方法中生成的东西,有没有办法只在第二个测试执行时模拟它打电话?
    • 更新了答案以包含此问题的解决方案。
    【解决方案2】:

    除了call(input_dir) 对我不起作用之外,原始帖子应该可以工作

    @mock.patch('shutil.rmtree')
    def test_convert_with_rmv(self, rm_mock):
        input_dir = 'resources/files'
    
        rm_mock.return_value = 'REMOVED'
        file_converter = FileConverter(input_dir)
        file_converter.convert_files(True)
        rm_mock.assert_called_with(input_dir)
        self.assertEqual(rm_mock.return_value, 'REMOVED')
    

    test_convert_with_rmv 没有办法删除input_dir,它可能一开始就没有创建。您可以在 convert_files 调用之前和之后的每个测试中断言此语句:

        self.asserTrue(os.path.isdir(input_dir))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-18
      • 2020-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 2020-08-28
      相关资源
      最近更新 更多