requests headers python unit-testing testing mocking

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''


Estoy usando Mock''s decorador de parches Mock''s :

from mock import patch [...] @patch(''urllib.urlopen'') def test_foo(self, urlopen_mock): urlopen_mock.return_value = MyUrlOpenMock()


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.