【问题标题】:Mocking Files In Python Unittest In Imported Modules在导入模块中的 Python 单元测试中模拟文件
【发布时间】:2017-09-07 20:27:16
【问题描述】:

我很乐意承认在单元测试方面有点过火了。 虽然我通过了测试,但我发现我的解决方案并不优雅,我很好奇是否有人有更清洁的解决方案。

被测试的类:

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())

感谢您的宝贵时间。

【问题讨论】:

  • 这似乎不无道理。对于不同的解决方案,您不能在实例化Config() 实例之前在模块中设置BASE_DIRROOT_DIRCONFIG_FILE 吗?如果您的Config 类作为可选参数接受配置文件的路径怎么办?
  • 我认为你不应该测试ConfigParser。您应该测试 _read_config_file 是否按照您的意思执行,即读取配置文件并在它未能执行此操作时引发异常。
  • 谢谢,@larsks。我也看到了该实用程序,但是,目前,我有兴趣将所有与配置相关的信息保存在一个地方(即,将 .ini 文件的名称保存在 .ini 文件中)。真正给我带来麻烦的是ConfigParser 类在调用.read 时如何设置文件信息。我宁愿只是修补一个使用 ascii 字符来设置数据的模拟文件对象,但是该类的设计方式并不那么直观。
  • @OluwafemiSule - 我也用上面的几种变体进行了测试,如下所示:with self.assertRaises(FileNotFoundError):config.Config._read_config_file(config.ConfigParser()) *(绕过隐藏方法前缀的奇怪语法)
  • *上面的错字,(即在Config文件中保留.ini文件的名称)

标签: python python-unittest configparser python-mock


【解决方案1】:

我找到了!

我必须从一些导入开始:from io import TextIOWrapper, BytesIO

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

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

@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')

【讨论】:

    猜你喜欢
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2018-08-11
    • 2011-01-16
    • 2012-08-08
    相关资源
    最近更新 更多