Могу ли я "подделать" пакет (или хотя бы модуль) в python для тестирования?
Я хочу подделать пакет в python. Я хочу что-то определить, чтобы код мог выполнять
from somefakepackage.morefakestuff import somethingfake
И somefakepackage определяется в коде, и все под ним. Это возможно? Причина этого заключается в том, чтобы обмануть мой unittest, что я получил пакет (или, как я сказал в названии, модуль) в пути python, который на самом деле просто что-то издевается над этим unittest.
Спасибо!
Ответы
Ответ 1
Конечно. Определите класс, поместите нужный материал внутри него, присвойте классу sys.modules["classname"]
.
class fakemodule(object):
@staticmethod
def method(a, b):
return a+b
import sys
sys.modules["package.module"] = fakemodule
Вы также можете использовать отдельный модуль (назовите его fakemodule.py
):
import fakemodule, sys
sys.modules["package.module"] = fakemodule
Ответ 2
Да, вы можете создать поддельный модуль:
from types import ModuleType
m = ModuleType("fake_module")
import sys
sys.modules[m.__name__] = m
# some scripts may expect a file
# even though this file doesn't exist,
# it may be used by Python for in error messages or introspection.
m.__file__ = m.__name__ + ".py"
# Add a function
def my_function():
return 10
m.my_function = my_function
Обратите внимание, что в этом примере используется фактический модуль (ModuleType
), поскольку некоторые
Код Python может ожидать модули, (а не фиктивный класс).
Это можно сделать в служебную функцию:
def new_module(name, doc=None):
import sys
from types import ModuleType
m = ModuleType(name, doc)
m.__file__ = name + '.py'
sys.modules[name] = m
return m
print(new_module("fake_module", doc="doc string"))
Теперь могут выполняться другие скрипты:
import fake_module
Ответ 3
Вы можете подделать его классом, который ведет себя как somethingfake
:
try:
from somefakepackage.morefakestuff import somethingfake
except ImportError:
class somethingfake(object):
# define what you'd expect of somethingfake, e.g.:
@staticmethod
def somefunc():
...
somefield = ...
Ответ 4
Я взял некоторые идеи из других ответов и превратил их в декоратор Python @modulize
, который преобразует функцию в модуль. Этот модуль можно импортировать, как обычно. Вот пример.
@modulize('my_module')
def my_dummy_function(__name__): # the function takes one parameter __name__
# put module code here
def my_function(s):
print(s, 'bar')
# the function must return locals()
return locals()
# import the module as usual
from my_module import my_function
my_function('foo') # foo bar
Код декоратора выглядит следующим образом
import sys
from types import ModuleType
class MockModule(ModuleType):
def __init__(self, module_name, module_doc=None):
ModuleType.__init__(self, module_name, module_doc)
if '.' in module_name:
package, module = module_name.rsplit('.', 1)
get_mock_module(package).__path__ = []
setattr(get_mock_module(package), module, self)
def _initialize_(self, module_code):
self.__dict__.update(module_code(self.__name__))
self.__doc__ = module_code.__doc__
def get_mock_module(module_name):
if module_name not in sys.modules:
sys.modules[module_name] = MockModule(module_name)
return sys.modules[module_name]
def modulize(module_name, dependencies=[]):
for d in dependencies: get_mock_module(d)
return get_mock_module(module_name)._initialize_
Проект можно найти здесь, на GitHub. В частности, я создал это для соревнований по программированию, которые позволяют конкурсанту подавать только один файл .py
. Это позволяет разработать проект с несколькими .py файлами, а затем объединить их в один файл .py
в конце.