Другое поведение unittest.mock на Python 2/3 - PullRequest
0 голосов
/ 06 августа 2020

У меня есть unittest, который должен быть совместим как с python 2, так и с 3. Это выглядит так:

def test_getModulePath_BuildInThrowsAnException(self):
    resource = mock.Mock(spec=some.module.SomeClass)
    resource.name = 'BuiltIn'
    resource.parent = resource

    if sys.version_info[0] == 3:  # Python 3
        patched_class = '_frozen_importlib_external.SourceFileLoader'
    else:  # Python 2
        patched_class = 'pkgutil.ImpLoader'

    with mock.patch(patched_class) as loader_mock:
        loader_mock.side_effect = MyException
        try:
            result = MyClass._get_module_path(resource)
            self.assertIsNone(result)
        except MyException as e:
            self.fail(e)

Метод, который я хочу проверить:

@classmethod
def _get_module_path(cls, resource):
    ...
    try:
        loader = pkgutil.get_loader(resource.name)
    except MyException as e:
        return None
    ...
    return loader.get_filename() 

Проблема в том, что pkgutil.get_loader() возвращает разные объекты, которые зависят от версии python. На Py2 все в порядке, загрузчик выдает ошибку как side_effect, метод возвращает None и loader_mock.called = True. Но на загрузчике Py3 side_effect не работает, и метод переходит к return loader.gt_filename(). Любые идеи? Python версия: 2.7.15 и 3.6.3

1 Ответ

0 голосов
/ 20 августа 2020

Я думаю, проблема связана с системой импорта python, потому что объект, возвращаемый get_loader, является точным _frozen_importlib_external.SourceFileLoader, но side_effect не возникает. Проблема была решена путем исправления функции pkgutil.get_loader, а не класса возвращаемого объекта:

        with mock.patch('pkgutil.get_loader', side_effect=MyException):
            try:
                result = MyClass._get_module_path(resource)
                self.assertIsNone(result)
            except MyException as e:
                self.fail(e)

Надеюсь, это кому-то поможет. Спасибо.

...