如何检查写入 mock_open() 假文件的内容?

How to check what was written to a mock_open() fake file?

我有一个高效的功能,可以读取一个文件,在某些情况下还可以(不止一次)写入另一个文件(带有详细的错误输出)。

我能够模拟文件读取并在单元测试中给出特定的文件内容。但我不知道如何测试写入第二个文件的内容,该文件也通过 mock_open().

模拟

重要的一点是,我对在单元测试时将真实文件写入文件系统不感兴趣。

这是有效代码:

import pathlib

def my_prod_code(fp):
    with fp.open('r') as if:
        result = if.read()

    with fp.with_suffix('.error.out').open('w') as of:
        of.write(f'Read {result}.')
        of.write('FIN.')

    return result

那就是单元测试

import unittest
from unittest import mock
import pathlib

class MyTest(unittest.TestCase):
    def test_foobar(self, mock_unlink):
        opener = mock.mock_open(read_data='foobar')

        with mock.patch('pathlib.Path.open', opener):
            result = my_prod_code(pathlib.Path('file.in'))
            self.assertEqual(result, 'foobar')
            
            # Want to check for the written content also

没有 built-in 方法可以做到这一点,因此您要么必须在 mock 中添加自己的处理,要么使用一些伪造文件系统的包。

添加您自己的处理意味着实现您自己的 write,例如像这样:

class MockWriter:
    """Collect all written data."""
    def __init__(self):
        self.contents = ''

    def write(self, data):
        self.contents += data

class MyTest(unittest.TestCase):
    def test_foobar(self):
        opener = mock.mock_open(read_data='foobar')
        writer = MockWriter()
        # replace the write method in the mock with your own
        opener.return_value.write = writer.write
        with mock.patch('pathlib.Path.open', opener) as f:
            result = my_prod_code(pathlib.Path('file.in'))
            self.assertEqual(result, 'foobar')
            self.assertEqual(writer.contents, 'Read foobar.FIN.')

另一种可能是使用伪造的文件系统,例如 pyfakefs:

from pyfakefs.fake_filesystem_unittest import TestCase

class MyTest(TestCase):
    def setUp(self):
        self.setUpPyfakefs()

    def test_foobar(self):
        self.fs.create_file('file.in', contents='foobar')
        result = my_prod_code(pathlib.Path('file.in'))
        self.assertEqual(result, 'foobar')
        path = pathlib.Path('file.error.out')
        self.assertEqual(path.read_text(), 'Read foobar.FIN.')

这样,您就不必自己进行模拟,并且可以使用标准文件系统函数,缺点是您需要一个额外的包来产生一些测试开销。

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