2015-03-31 14 views
5

Di seguito è riportato un frammento di codice del mio modulo api.pyNon in grado di prendere in giro urllib2.urlopen usando mock.patch di Python

# -*- coding: utf-8 -*- 

from urllib2 import urlopen 
from urllib2 import Request 

class API: 

    def call_api(self, url, post_data=None, header=None): 
     is_post_request = True if (post_data and header) else False 
     response = None 
     try: 
      if is_post_request: 
       url = Request(url = url, data = post_data, headers = header) 
      # Calling api 
      api_response = urlopen(url) 
      response = api_response.read() 
     except Exception as err: 
      response = err 

     return response 

Sto cercando di deridere urllib2.urlopen in unittest del modulo di cui sopra. Ho scritto

# -*- coding: utf-8 -*- 
# test_api.py 

from unittest import TestCase 
import mock 

from api import API 

class TestAPI(TestCase): 

    @mock.patch('urllib2.Request') 
    @mock.patch('urllib2.urlopen') 
    def test_call_api(self, urlopen, Request): 
     urlopen.read.return_value = 'mocked' 
     Request.get_host.return_value = 'google.com' 
     Request.type.return_value = 'https' 
     Request.data = {} 
     _api = API() 
     assert _api.call_api('https://google.com') == 'mocked' 

Dopo ho eseguito l'unittest, ottengo un'eccezione

<urlopen error unknown url type: <MagicMock name='Request().get_type()' id='159846220'>> 

Che cosa mi manca? Per favore aiutatemi.

risposta

7

Stai aggiustando le cose sbagliate: dai un'occhiata a Where to patch.

In api.py da

from urllib2 import urlopen 
from urllib2 import Request 

si crea un riferimento locale per urlopen e Request nel file. Con mock.patch('urllib2.urlopen') si sta patcinando il riferimento originale e si lascia intatto quello di api.py.

Quindi, sostituire le patch da

@mock.patch('api.Request') 
@mock.patch('api.urlopen') 

dovrebbe risolvere il problema .... ma non è sufficiente.

Nel tuo caso prova api.Request non sono utilizzati, ma urllib2.urlopen() creare un Request con l'uso della versione corretta: è per questo che è un Request().get_type()MagicMock.

Per una correzione completa, è necessario modificare il test. In primo luogo il codice:

@mock.patch('api.urlopen', autospec=True) 
def test_call_api(self, urlopen): 
    urlopen.return_value.read.return_value = 'mocked' 
    _api = API() 
    self.assertEqual(_api.call_api('https://google.com'), 'mocked') 
    urlopen.assert_called_with('https://google.com') 

Ora il chiarimento ... Nel tuo test non si chiama Request() perché si passa solo il primo parametro, quindi ho rimosso cerotto inutile. Inoltre, si applica la patch alla funzione urlopen e non all'oggetto urlopen, il che significa che il metodo read() che si desidera deridere è un metodo di ritorno dell'oggetto tramite chiamata urlopen().

Infine aggiungo un controllo su urlopen chiamata e autospec=True che è sempre una buona pratica.

+0

Ho apportato le modifiche. Il valore di '_api.call_api ('https://google.com')' è '' che non corrisponde a "mocked". Perché? Post scriptum Ho aggiornato l'ultima riga con 'assert' in test_api.py – Hussain

+0

Dovrei riscrivere il test .... Troppi dettagli sono sbagliati. –

+0

@Hussain ora dovrebbe essere OK –

Problemi correlati