【问题标题】:Mocking open function with mock_open [duplicate]用 mock_open 模拟打开函数 [重复]
【发布时间】:2017-03-29 08:41:10
【问题描述】:

所以我的 Django 应用业务逻辑中有我想要测试的功能:

def parse_sectors_from_csv():
    sectors_csv = open(os.path.join(settings.BASE_DIR, 'sector', 'fixtures', 'sectors.csv'))
    sectors_csv_reader = csv.DictReader(sectors_csv)
    return [
        {
            'model': 'sector.sector',
            'id': index,
            'fields': {
                'name': row.get('Sector'),
                'slug': slugify(row['Sector']),
                'type_id': row.get('Type_Id')
            }
        }
        for index, row in enumerate(sectors_csv_reader, 1)
    ]

我已经测试了它是否存在文件和标题行。

现在我想模拟

open(os.path.join(settings.BASE_DIR, 'sector', 'fixtures', 'sectors.csv'))

在我的 test.py 中我写了

with patch('__builtin__.open', mock_open(read_data=sectors_csv_mock), create=True) as m:
        sectors = service.parse_sectors_from_csv()
        print('Sectors:', sectors)
        self.assertEqual(expected_sectors, sectors)

但据我了解,它会在打印Sectors: [] 时传递空文件以发挥作用

我读了几遍 mock_open dock 还是不明白。

>>> with patch('__main__.open', mock_open(read_data='bibble')) as m:
...     with open('foo') as h: # what's happening here?
...         result = h.read() # here?
...
>>> m.assert_called_once_with('foo') # and here?
>>> assert result == 'bibble'

【问题讨论】:

    标签: python django python-2.7 unit-testing mocking


    【解决方案1】:

    模拟的第一条规则:不要在定义它们的地方模拟对象/方法,而是在使用它们的地方模拟它们。所以不是__builtin__.open,而是my_app.my_file.open

    其次,我不知道mock_open 是什么,但你可以用正常的模拟方式来做:

    with mock.patch('my_app.my_file.open') as mocked_open:
        mocked_open.return_value = StringIO('foo')
    

    无论如何这都行得通。

    附言

    总是在处理文件时使用with

    【讨论】:

    • 谢谢!那行得通。
    【解决方案2】:

    每当我觉得需要嘲笑时,我首先会问自己这是否是 按照这些思路重构代码是可行的:

    1. 算法上不重要的东西,我可能想要进行单元测试 用实际的断言。

    2. 东西很简单,我要么 (a) 几乎不需要测试它,要么 (b) 可以 使用仅练习代码的单个端到端测试进行充分测试 不做任何断言。

    例如:

    ####
    # Hardly worth testing.
    ####
    
    def parse_sectors_from_csv():
        file_path = sectors_file_path()
        with open(file_path) as fh:
            return do_parse_sectors_from_csv(fh)
    
    ####
    # Easily tested without mocks.
    ####
    
    def do_parse_sectors_from_csv(fh):
        reader = csv.DictReader(fh)
        return do_parse_sectors_from_csv(reader)
    
    def sectors_file_path():
        return os.path.join(settings.BASE_DIR, 'sector', 'fixtures', 'sectors.csv')
    
    def parse_sectors_from_csv(rows):
        return [
            {
                'model': 'sector.sector',
                'id': index,
                'fields': {
                    'name': row.get('Sector'),
                    'slug': slugify(row['Sector']),
                    'type_id': row.get('Type_Id')
                }
            }
            for index, row in enumerate(rows, 1)
        ]
    

    【讨论】:

    • 感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 2023-02-26
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多