2011-02-25 8 views
12

Quiero falsificar un paquete en python. Quiero definir algo para que el código puede hacer¿Puedo "falsificar" un paquete (o al menos un módulo) en python con fines de prueba?

from somefakepackage.morefakestuff import somethingfake 

Y somefakepackage se define en el código y así es todo por debajo de ella. ¿Es eso posible? La razón para hacer esto es engañar a mi unittest de que obtuve un paquete (o como dije en el título, un módulo) en el camino de python, que en realidad es algo ridículo para esta prueba unitaria.

Gracias!

+2

La palabra que está buscando es ___mock___. Esta pregunta podría ayudar, http://stackoverflow.com/questions/295438 –

Respuesta

19

Sure. Defina una clase, ponga las cosas que necesita dentro de eso, asigne la clase al sys.modules["classname"].

class fakemodule(object): 

    @staticmethod 
    def method(a, b): 
     return a+b 

import sys 
sys.modules["package.module"] = fakemodule 

También es posible usar un módulo separado (lo llaman fakemodule.py):

import fakemodule, sys 

sys.modules["package.module"] = fakemodule 
+5

Un truco con esto es asegurarse de insertar también un módulo falso para 'paquete' con' __path__ = [] 'como un atributo de nivel superior. Sin eso, la jerarquía del módulo está incompleta, lo que puede confundir algunas herramientas. – ncoghlan

+0

Agradable, buena adición. – kindall

+0

Solo para agregar. Si está importando un submódulo, p. 'import a.b.c', es posible que necesite asignar módulos falsos a ' sys.modules ["a"] ',' sys.modules ["a.b"] 'and' sys.modules ["a.b.c"] ' –

2

Usted podría fingir con una clase que se comporta como 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

Sí, se puede hacer un módulo falso:

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 

Tenga en cuenta que en este ejemplo está usando un módulo real (de ModuleType) ya que algunos códigos de Python pueden esperar módulos (en lugar de una clase ficticia).

Esto se puede convertir en una función de utilidad:

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

Ahora otros scripts pueden correr:

import fake_module 
1

Tomé algunas de las ideas de las otras respuestas y los convirtió en un decorador de Python @modulize que convierte una función en un módulo. Este módulo se puede importar como de costumbre. Aquí hay un ejemplo.

@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 

El código para el decorador es el siguiente

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_ 

El proyecto se puede encontrar here on GitHub. En particular, he creado esto para concursos de programación que solo permiten al concursante enviar un único archivo .py. Esto le permite a uno desarrollar un proyecto con múltiples archivos .py y luego combinarlos en un solo archivo .py al final.

Cuestiones relacionadas