Поддельный модуль, используемый другими модулями

Есть ли возможность подделать модуль, который используется (импортируется) другими модулями, которые я использую в своих тестах?

Пример: это мой test.py:

import unittest 
import module1
//test code here
module1.some_method()
//test code here

Это module1.py:

import module_i_want_to_fake
//module code here

На примере: вопрос: как я могу подделать module_i_want_to_fake в test.py


person Jacob Jedryszek    schedule 13.03.2013    source источник
comment
Какова причина? Вы можете сделать import module1 as m1 Или использовать другое имя в качестве ссылки на него.   -  person ninMonkey    schedule 14.03.2013
comment
но когда я импортирую модуль1, тогда модуль1 будет импортировать module_i_want_to_fake, но я хочу, чтобы он импортировал my_fake_module   -  person Jacob Jedryszek    schedule 14.03.2013
comment
Итак, вы хотите из-за пределов module1 перехватывать его операторы import, чтобы вы могли подставлять разные модули?   -  person abarnert    schedule 14.03.2013
comment
Возможный дубликат Могу ли я подделать пакет (или хотя бы модуль) в Python для тестирования?   -  person user    schedule 13.01.2017


Ответы (2)


Когда вы делаете import foo, если sys.modules['foo'] уже существует, интерпретатор просто возвращает это вместо того, чтобы выполнять новый импорт.

Таким образом, чтобы сфальсифицировать оператор import module1, просто введите значение перед загрузкой module1. Это немного хакерски, но очень просто. Например:

mytest.py:

import sys
import unittest 
import my_fake_module
sys.modules['module_i_want_to_fake'] = my_fake_module
import module1
//test code here
module1.some_method()
//test code here

модуль1.py:

import module_i_want_to_fake
print(module_i_want_to_fake)

Это напечатает что-то вроде этого:

<module 'my_fake_module' from 'my_fake_module.pyc'>

Если вам нужно более тщательно подделать module1 (даже если он попытается изучить модуль), вы можете создать новый модуль (через types.ModuleType) с кодом из my_fake_module, но с именем 'module_i_want_to_fake' и любыми другими изменениями, которые вы хотите.

Если вам нужно сделать это более динамично, чем это можно сделать, просто предварительно переименовав модули статически, вы можете создать обработчик импорта, как описано в PEP 302. Это требует от вас повторной реализации значительной части механизма импорта, что является огромной проблемой в версии 2.x, но importlib в 3.1+ делает это намного проще.

К счастью, обычно вам не нужно делать ни того, ни другого.

person abarnert    schedule 13.03.2013

В python3 я делаю это:

Создать простой поддельный класс в модуле

# module test.py
thismodule = sys.modules[__name__]
setattr(thismodule, "something", type("something", (), {}))

Это круто, но вы, вероятно, хотите сгенерировать из файла данных конфигурации.

Создать поддельный класс в модуле из файла cfg

# module test.py
import configparser

cfg = configparser.ConfigParser()
cfg.read("/path/to/fname.ini")

for section in cfg.sections():
    name = cfg[str(section)]['name']
    setattr(thismodule, name, type(name, (), {}))

Хорошо, теперь попробуем в модуле1

# Import only the main module
import test

# now you can use as you want
test.something

Наслаждаться!!

person macm    schedule 28.11.2014