【问题标题】:Testing function taking multiple files测试功能获取多个文件
【发布时间】:2021-11-10 21:56:09
【问题描述】:

我有一个函数,它接受 3 个文件并返回一个包含文件数据的元组。 例如:

第一个文件:

SVF2018-05-24_12:02:58.917

NHR2018-05-24_12:02:49.914

第二个文件:

SVF2018-05-24_1:04:11.332

NHR2018-05-24_1:04:02.979

第三个文件:

SVF_塞巴斯蒂安维特尔_法拉利

NHR_Nico Hulkenberg_RENAULT

我得到这样的结果:

result = (
        [('SVF', '2018-05-24_12:02:58.917'), ('NHR', '2018-05-24_12:02:49.914')],
        [('SVF', '2018-05-24_1:04:11.332'), ('NHR', '2018-05-24_1:04:02.979')],
        [['SVF', 'Sebastian Vettel', 'FERRARI'], ['NHR', 'Nico Hulkenberg', 'RENAULT']]
) 

函数本身如下所示:

def read_files(start_log, end_log, abbr) -> tuple:
    """
    Takes two .log files - start and end, and a file containing abbreviation explanations.
    Processes the data from the files and returns a tuple of lists containing lines for each file.
    """
    for argument in [start_log, end_log, abbr]:
        if not os.path.isfile(argument):
            raise FileNotFoundError('Attribute must be a file.')

        with open(argument, 'r') as f:
            if argument == abbr:
                abbr_lines = [line.strip().split('_') for line in f]
            elif argument == start_log:
                start_lines = [(line[:3], line.strip()[3:]) for line in f]
                start_lines.pop()
            else:
                end_lines = [(line[:3], line.strip()[3:]) for line in f]
    return start_lines, end_lines, abbr_lines

我需要为它写一个测试。

我发现错误没有问题:

class ReadFilesTestCase(unittest.TestCase):
    def test_file_not_found_error(self):
        with self.assertRaises(FileNotFoundError):
            read_files('a.txt', 'b.txt', 'c.txt')

但我真的很难将多个文件模拟为函数的参数。

我一直在尝试这样做:

class ReadFilesTestCase(unittest.TestCase):
    def setUp(self):
        self.file_1 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
        self.file_2 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))
        self.file_3 = mock.patch("builtins.open", mock.mock_open(read_data=self.file_1_data))

    def test_read_files:
        self.assertEqual(read_files(self.file_1, self.file_2, self.file_3), self.result)

但我遇到了 FileNotFoundError。我也试过@mock.patch.multiple - 效果不佳。

我想知道是否可以模拟文件,所以我只是这样写:

self.assertEqual(read_files(fake_file_1, fake_file_2, fake_file_3), self.result)

我应该使用什么技术?我很感激任何建议。

【问题讨论】:

    标签: python unit-testing mocking


    【解决方案1】:

    这里的问题是mock_open 只能为所有文件名伪造open,而不是特定文件名。 我在这里看到两种可能性:滚动你自己的 open 模拟而不是使用 open_mock 使用 side_effect (有点难看,并且与实现紧密耦合),或者使用类似 pyfakefs 的东西来模拟文件系统(不那么丑,但重量级)。

    第一种方法可能如下所示:

    class ReadFilesTestCase(unittest.TestCase):
    
        @mock.patch("os.path.isfile", return_value=True)
        def test_read_files(self, mocked_isfile):
            # as we have to mock the for look in the open file,
            # we need to provide the lines as arrays (this will probably go in setUp)
            file1_lines = ["SVF2018-05-24_12:02:58.917",
                           "NHR2018-05-24_12:02:49.914"]
            file2_lines = ["SVF2018-05-24_1:04:11.332",
                           "NHR2018-05-24_1:04:02.979"]
            file3_lines = ["SVF_Sebastian Vettel_FERRARI",
                           "NHR_Nico Hulkenberg_RENAULT"]
            open_mock = MagicMock(name='open', spec=open)
            # we have to first mock __enter__ to account for context manager
            # then we use side_effect to define the result subsequent calls to open()
            open_mock.return_value.__enter__.side_effect = [
                file1_lines, file2_lines, file3_lines
            ]
            with mock.patch('builtins.open', open_mock):
                # the file names don't matter in this case
                assert read_files("f1", "f2", "f3") == expected_result
    

    对于第二种方法,您需要pyfakefs

    from pyfakefs import fake_filesystem_unittest
    
    class ReadFilesTestCase(fake_filesystem_unittest.TestCase):
    
        def setUp(self):
            self.setUpPyfakefs()
    
        def test_read_files(self, mocked_isfile):
            # we create the needed files in the fake filesystem
            self.fs.create_file("a.txt", 
                contents="SVF2018-05-24_12:02:58.917\nNHR2018-05-24_12:02:49.914")
            self.fs.create_file("b.txt", 
                contents="SVF2018-05-24_1:04:11.332\nNHR2018-05-24_1:04:02.979")
            self.fs.create_file("c.txt",
                contents="SVF_Sebastian Vettel_FERRARI\nNHR_Nico Hulkenberg_RENAULT")
            
            # now the files exist in the fake filesystem (e.g. in memory), and you can just use them    
            assert read_files("a.txt", "b.txt", "c.txt") == expected_result
    

    免责声明:我是 pyfakefs 的贡献者。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多