75 votes

Comment un module python simulé / stub comme urllib

J'ai besoin de tester une fonction qui doit interroger une page sur un serveur externe en utilisant urllib.urlopen (il utilise également urllib.urlencode). Le serveur pourrait être en panne, la page pourrait changer; Je ne peux pas compter dessus pour un test.

Quel est le meilleur moyen de contrôler les retours d'urllib.urlopen?

100voto

Clint Miller Points 6339

Une autre approche simple est d'avoir votre test de remplacer urllib de l' urlopen() fonction. Par exemple, si votre module a

import urllib

def some_function_that_uses_urllib():
    ...
    urllib.urlopen()
    ...

Vous pouvez définir votre test comme ceci:

import mymodule

def dummy_urlopen(url):
    ...

mymodule.urllib.urlopen = dummy_urlopen

Ensuite, lors de vos tests appeler des fonctions en mymodule, dummy_urlopen() sera appelée à la place du réel urlopen(). Dynamique des langages comme Python super facile à talon des méthodes et des classes pour les tests.

Voir les articles de mon blog à http://softwarecorner.wordpress.com/ pour plus d'informations sur déraciner les dépendances pour les tests.

72voto

Dinoboff Points 1090

J'utilise le patch décorateur de Mock :

 from mock import patch

[...]

@patch('urllib.urlopen')
def test_foo(self, urlopen_mock):
    urlopen_mock.return_value = MyUrlOpenMock()
 

26voto

Damir Zekić Points 7517

Avez-vous regardé Mox ? Il devrait faire tout ce dont vous avez besoin. Voici une session interactive simple illustrant la solution dont vous avez besoin:

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

14voto

Gabriel Falcão Points 456

HTTPretty fonctionne exactement de la même manière que FakeWeb. HTTPretty fonctionne dans la couche socket, il devrait donc intercepter toutes les librairies clientes python http. Il est testé contre urllib2, httplib2 et les requêtes

 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"
 

8voto

Douglas Leeder Points 29986

Le meilleur moyen de gérer cela est probablement de scinder le code afin que la logique qui traite le contenu de la page soit scindée du code qui récupère la page.

Ensuite, passez une instance du code d'extraction dans la logique de traitement, puis remplacez-la facilement par un simulateur d'extraction pour le test unitaire.

par exemple

 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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X