Intento esto por casi dos horas, sin suerte.Mocking ImportError en Python
que tienen un módulo que tiene este aspecto:
try:
from zope.component import queryUtility # and things like this
except ImportError:
# do some fallback operations <-- how to test this?
Más adelante en el código:
try:
queryUtility(foo)
except NameError:
# do some fallback actions <-- this one is easy with mocking
# zope.component.queryUtility to raise a NameError
¿Alguna idea?
EDIT:
no parece la sugerencia de Alex a trabajar:
>>> import __builtin__
>>> realimport = __builtin__.__import__
>>> def fakeimport(name, *args, **kw):
... if name == 'zope.component':
... raise ImportError
... realimport(name, *args, **kw)
...
>>> __builtin__.__import__ = fakeimport
al ejecutar las pruebas:
[email protected] ~/work/ao.shorturl $ ./bin/test --coverage .
Running zope.testing.testrunner.layer.UnitTests tests:
Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds.
Error in test /home/aatiis/work/ao.shorturl/src/ao/shorturl/shorturl.txt
Traceback (most recent call last):
File "/usr/lib64/python2.5/unittest.py", line 260, in run
testMethod()
File "/usr/lib64/python2.5/doctest.py", line 2123, in runTest
test, out=new.write, clear_globs=False)
File "/usr/lib64/python2.5/doctest.py", line 1361, in run
return self.__run(test, compileflags, out)
File "/usr/lib64/python2.5/doctest.py", line 1282, in __run
exc_info)
File "/usr/lib64/python2.5/doctest.py", line 1148, in report_unexpected_exception
'Exception raised:\n' + _indent(_exception_traceback(exc_info)))
File "/usr/lib64/python2.5/doctest.py", line 1163, in _failure_header
out.append(_indent(source))
File "/usr/lib64/python2.5/doctest.py", line 224, in _indent
return re.sub('(?m)^(?!$)', indent*' ', s)
File "/usr/lib64/python2.5/re.py", line 150, in sub
return _compile(pattern, 0).sub(repl, string, count)
File "/usr/lib64/python2.5/re.py", line 239, in _compile
p = sre_compile.compile(pattern, flags)
File "/usr/lib64/python2.5/sre_compile.py", line 507, in compile
p = sre_parse.parse(p, flags)
AttributeError: 'NoneType' object has no attribute 'parse'
Error in test BaseShortUrlHandler (ao.shorturl)
Traceback (most recent call last):
File "/usr/lib64/python2.5/unittest.py", line 260, in run
testMethod()
File "/usr/lib64/python2.5/doctest.py", line 2123, in runTest
test, out=new.write, clear_globs=False)
File "/usr/lib64/python2.5/doctest.py", line 1351, in run
self.debugger = _OutputRedirectingPdb(save_stdout)
File "/usr/lib64/python2.5/doctest.py", line 324, in __init__
pdb.Pdb.__init__(self, stdout=out)
File "/usr/lib64/python2.5/pdb.py", line 57, in __init__
cmd.Cmd.__init__(self, completekey, stdin, stdout)
File "/usr/lib64/python2.5/cmd.py", line 90, in __init__
import sys
File "<doctest shorturl.txt[10]>", line 4, in fakeimport
NameError: global name 'realimport' is not defined
Sin embargo, hace trabajo cuando corro el mismo código de la consola interactiva de python.
más Editar:
estoy usando zope.testing
y un archivo de prueba, shorturl.txt
que tiene todas las pruebas específicas para esta parte de mi módulo. Primero estoy importando el módulo con zope.component
disponible, para demostrar & probar el uso habitual. La ausencia de paquetes zope.*
se considera un caso extremo, así que lo estoy probando más tarde. Por lo tanto, tengo que reload()
mi módulo, después de hacer zope.*
no está disponible, de alguna manera.
Hasta ahora incluso he intentado usar tempfile.mktempdir()
y vacío zope/__init__.py
y zope/component/__init__.py
archivos en el tempdir, a continuación, insertar tempdir a sys.path[0]
, y la eliminación de los viejos zope.*
paquetes de sys.modules
.
No funcionó tampoco.
AÚN MÁS EDIT:
Mientras tanto, he intentado esto:
>>> class NoZope(object):
... def find_module(self, fullname, path):
... if fullname.startswith('zope'):
... raise ImportError
...
>>> import sys
>>> sys.path.insert(0, NoZope())
Y funciona bien para el espacio de nombres del conjunto de pruebas (= para todas las importaciones en shorturl.txt
) , pero no se ejecuta en mi módulo principal, ao.shorturl
. Ni siquiera cuando yo reload()
él. ¿Alguna idea de por qué?
>>> import zope # ok, this raises an ImportError
>>> reload(ao.shorturl) <module ...>
Importación zope.interfaces
plantea una ImportError
, por lo que no llega a la parte donde puedo importar zope.component
y que permanece en el espacio de nombres ao.shorturl. ¡¿Por qué?!
>>> ao.shorturl.zope.component # why?!
<module ...>
¡Ah, gracias! Por alguna razón, traté de hacer 'def __import __()', pero no lo asigné a 'builtin .__ import__'; tonto de mí. Interesante, estaba leyendo tu respuesta aquí: http://stackoverflow.com/questions/2216828/mock-y-of-from-x-import-y-in-doctest-python/2217512#2217512 - ¿Crees? ¿Esta situación sería más fácil si no importara queryUtility al alcance de mi módulo? –
@Attila, si hiciste 'from zope import component' y luego usaste' component.queryUtility', sería más fácil, por ejemplo, usar lo real algunas veces, y una versión falsa/falsa en otros tiempos.Como escribí en esa respuesta, lo recomiendo como algo general, y es parte de la forma en que codificamos Python en Google (a veces una cláusula 'as' para acortar el nombre que uno importa está garantizada, por supuesto, pero eso no t cambiar la semántica). –
Si lo hace 'desde el componente de importación zope', BTW, su función' __import__' -like verá '' zope'' como el argumento 'name', y' 'component'' como un elemento en el argumento 'fromlist' (el único, a menos que lo haga 'desde zope import this, that, component' o similar ;-); así que asegúrese de disparar en consecuencia. –