requests - urllib request headers python
¿Cómo puede un módulo simulado/stub python como urllib (7)
¿Le Mox una mirada a Mox ? Debería hacer todo lo que necesita. Aquí hay una sesión interactiva simple que ilustra la solución que necesita:
>>> import urllib
>>> # check that it works
>>> urllib.urlopen(''http://www.google.com/'')
<addinfourl at 3082723820L ...>
>>> # check what happens when it doesn''t
>>> urllib.urlopen(''http://hopefully.doesnotexist.com/'')
#-- snip --
IOError: [Errno socket error] (-2, ''Name or service not known'')
>>> # OK, let''s mock it up
>>> import mox
>>> m = mox.Mox()
>>> m.StubOutWithMock(urllib, ''urlopen'')
>>> # We can be verbose if we want to :)
>>> urllib.urlopen(mox.IgnoreArg()).AndRaise(
... IOError(''socket error'', (-2, ''Name or service not known'')))
>>> # Let''s check if it works
>>> m.ReplayAll()
>>> urllib.urlopen(''http://www.google.com/'')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.5/site-packages/mox.py", line 568, in __call__
raise expected_method._exception
IOError: [Errno socket error] (-2, ''Name or service not known'')
>>> # yay! now unset everything
>>> m.UnsetStubs()
>>> m.VerifyAll()
>>> # and check that it still works
>>> urllib.urlopen(''http://www.google.com/'')
<addinfourl at 3076773548L ...>
Necesito probar una función que necesita consultar una página en un servidor externo usando urllib.urlopen (también usa urllib.urlencode). El servidor podría estar caído, la página podría cambiar; No puedo confiar en ello para una prueba.
¿Cuál es la mejor manera de controlar lo que devuelve urllib.urlopen?
En caso de que no quiera incluso cargar el módulo:
import sys,types
class MockCallable():
""" Mocks a function, can be enquired on how many calls it received """
def __init__(self, result):
self.result = result
self._calls = []
def __call__(self, *arguments):
"""Mock callable"""
self._calls.append(arguments)
return self.result
def called(self):
"""docstring for called"""
return self._calls
class StubModule(types.ModuleType, object):
""" Uses a stub instead of loading libraries """
def __init__(self, moduleName):
self.__name__ = moduleName
sys.modules[moduleName] = self
def __repr__(self):
name = self.__name__
mocks = '', ''.join(set(dir(self)) - set([''__name__'']))
return "<StubModule: %(name)s; mocks: %(mocks)s>" % locals()
class StubObject(object):
pass
Y entonces:
>>> urllib = StubModule("urllib")
>>> import urllib # won''t actually load urllib
>>> urls.urlopen = MockCallable(StubObject())
>>> example = urllib.urlopen(''http://example.com'')
>>> example.read = MockCallable(''foo'')
>>> print(example.read())
''foo''
La forma más simple es cambiar su función para que no use necesariamente urllib.urlopen. Digamos que esta es su función original:
def my_grabber(arg1, arg2, arg3):
# .. do some stuff ..
url = make_url_somehow()
data = urllib.urlopen(url)
# .. do something with data ..
return answer
Agregue un argumento que es la función que debe usar para abrir la URL. Luego puede proporcionar una función simulada para hacer lo que necesite:
def my_grabber(arg1, arg2, arg3, urlopen=urllib.urlopen):
# .. do some stuff ..
url = make_url_somehow()
data = urlopen(url)
# .. do something with data ..
return answer
def test_my_grabber():
my_grabber(arg1, arg2, arg3, urlopen=my_mock_open)
Probablemente la mejor manera de manejar esto es dividir el código, de modo que la lógica que procesa los contenidos de la página se divida desde el código que capta la página.
Luego, pase una instancia del código de captura a la lógica de procesamiento, luego puede reemplazarlo fácilmente con una búsqueda de prueba para la prueba de la unidad.
p.ej
class Processor(oject):
def __init__(self, fetcher):
self.m_fetcher = fetcher
def doProcessing(self):
## use self.m_fetcher to get page contents
class RealFetcher(object):
def fetchPage(self, url):
## get real contents
class FakeFetcher(object):
def fetchPage(self, url):
## Return whatever fake contents are required for this test
HTTPretty funciona de la misma manera que FakeWeb. HTTPretty funciona en la capa de socket, por lo que debería funcionar interceptando cualquier biblioteca de cliente http de python. Se ha probado la batalla contra urllib2, httplib2 y solicitudes
import urllib2
from httpretty import HTTPretty, httprettified
@httprettified
def test_one():
HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/",
body="Find the best daily deals")
fd = urllib2.urlopen(''http://yipit.com'')
got = fd.read()
fd.close()
assert got == "Find the best daily deals"
Otro enfoque simple es hacer que su prueba anule la función urlopen()
de urlopen()
. Por ejemplo, si su módulo tiene
import urllib
def some_function_that_uses_urllib():
...
urllib.urlopen()
...
Podrías definir tu prueba así:
import mymodule
def dummy_urlopen(url):
...
mymodule.urllib.urlopen = dummy_urlopen
Luego, cuando las pruebas invocan funciones en mymodule
, se dummy_urlopen()
lugar de urlopen()
real urlopen()
. Los lenguajes dinámicos como Python hacen que sea muy fácil eliminar los métodos y las clases para probar.
Consulte las publicaciones de mi blog en http://softwarecorner.wordpress.com/ para obtener más información sobre cómo anular las dependencias para las pruebas.