在导入模块中的Python单元测试中模拟文件

时间:2017-09-07 20:27:17

标签: python python-unittest configparser python-mock

我很乐意承认单元测试会有点过分。 虽然我通过测试,但我觉得我的解决方案不够优雅,如果有人有更清洁的解决方案,我很好奇。

正在测试的课程:

class Config():

    def __init__(self):
        config_parser = ConfigParser()
        try:
            self._read_config_file(config_parser)
        except FileNotFoundError as e:
            pass

        self.token = config_parser.get('Tokens', 'Token', )

    @staticmethod
    def _read_config_file(config):
        if not config.read(os.path.abspath(os.path.join(BASE_DIR, ROOT_DIR, CONFIG_FILE))):
            raise FileNotFoundError(f'File {CONFIG_FILE} not found at path {BASE_DIR}{ROOT_DIR}')

丑陋的考验:

class TestConfiguration(unittest.TestCase):

    @mock.patch('config.os.path.abspath')
    def test_config_init_sets_token(self, mockFilePath: mock.MagicMock):
        with open('mock_file.ini', 'w') as file: #here's where it gets ugly
            file.write('[Tokens]\nToken: token')
        mockFilePath.return_value = 'mock_file.ini'

        config = Config()

        self.assertEqual(config.token, 'token')
        os.remove('mock_file.ini') #quite ugly
编辑:我的意思是我创建一个文件而不是嘲笑文件。 有没有人知道如何mock一个文件对象,同时拥有它的数据集,以便它读取ascii文本?这堂课深受埋葬。 除此之外,ConfigParser使用.read()设置数据的方式让我失望。当然,测试"工作",它没有做得很好。

对于那些询问其他测试行为的人,这里有另一个测试的例子:

@mock.patch('config.os.path.abspath')
def test_warning_when_file_not_found(self, mockFilePath: mock.MagicMock):
    mockFilePath.return_value = 'mock_no_file.ini'

    with self.assertRaises(FileNotFoundError):
        config.Config._read_config_file(ConfigParser())

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

我找到了它!

我不得不从一些导入开始:from io import TextIOWrapper, BytesIO

这允许创建文件对象:TextIOWrapper(BytesIO(b'<StringContentHere>'))

下一部分涉及深入configparser模块以查看它调用open(),以便mock.patch行为,并且,在这里我们拥有它,一个独立的单元测试!< / p>

@mock.patch('configparser.open') 
def test_bot_init_sets_token(self, mockFileOpen: mock.MagicMock):

    mockFileOpen.return_value = TextIOWrapper(BytesIO(b'[Tokens]\nToken: token'))

    config = Config()

    self.assertEqual(config.token, 'token')