2015-02-03 17 views
42

Ho una funzione (foo) che chiama un'altra funzione (bar). Se invocando bar() si alza un HttpError, voglio gestirlo appositamente se il codice di stato è 404, altrimenti controrilancia.Mocking di una funzione per generare un'eccezione per testare un blocco tranne

Sto provando a scrivere alcuni test unitari attorno alla funzione foo, prendendo in giro la chiamata a bar(). Sfortunatamente, non sono in grado di ottenere la chiamata falsa a bar() per generare un'eccezione che viene rilevata dal mio blocco except.

Ecco il mio codice che illustra il mio problema:

import unittest 
import mock 
from apiclient.errors import HttpError 


class FooTests(unittest.TestCase): 
    @mock.patch('my_tests.bar') 
    def test_foo_shouldReturnResultOfBar_whenBarSucceeds(self, barMock): 
     barMock.return_value = True 
     result = foo() 
     self.assertTrue(result) # passes 

    @mock.patch('my_tests.bar') 
    def test_foo_shouldReturnNone_whenBarRaiseHttpError404(self, barMock): 
     barMock.side_effect = HttpError(mock.Mock(return_value={'status': 404}), 'not found') 
     result = foo() 
     self.assertIsNone(result) # fails, test raises HttpError 

    @mock.patch('my_tests.bar') 
    def test_foo_shouldRaiseHttpError_whenBarRaiseHttpErrorNot404(self, barMock): 
     barMock.side_effect = HttpError(mock.Mock(return_value={'status': 500}), 'error') 
     with self.assertRaises(HttpError): # passes 
      foo() 

def foo(): 
    try: 
     result = bar() 
     return result 
    except HttpError as error: 
     if error.resp.status == 404: 
      print '404 - %s' % error.message 
      return None 
     raise 

def bar(): 
    raise NotImplementedError() 

ho seguito la Mock docs che dire che si dovrebbe impostare la side_effect di un'istanza Mock a una classe Exception avere la funzione deriso sollevare l'errore.

Ho anche guardato un altro StackOverflow Q & correlato come, e sembra che sto facendo la stessa cosa che stanno facendo causa ed Eccezione da sollevare dal loro finto.

Perché l'impostazione del side_effect di barMock non causando l'atteso Exception di essere sollevato? Se sto facendo qualcosa di strano, come dovrei andare a testare la logica nel mio blocco except?

+0

Sono abbastanza sicuro che la tua eccezione * sia * stata sollevata, ma non sono sicuro di come stai impostando il codice 'resp.status'. Da dove proviene 'HTTPError'? –

+0

@MartijnPieters 'HttpError' è una classe definita in [Google' apiclient' lib] (https://developers.google.com/api-client-library/python/) che usiamo in GAE. È '__init__' è definito con i parametri' (resp, content) 'quindi stavo tentando di creare un'istanza di simulazione per la risposta, con il codice di stato appropriato specificato. –

+0

Giusto, quindi è [questa classe] (https://github.com/google/google-api-python-client/blob/master/googleapiclient/errors.py#L35-L63); ma non è necessario all'utente 'return_value' allora; 'resp' non viene * chiamato *. –

risposta

54

Il tuo finto sta sollevando l'eccezione bene, ma manca il valore error.resp.status. Piuttosto che uso return_value, basta dire che Mockstatus è un attributo:

barMock.side_effect = HttpError(mock.Mock(status=404), 'not found') 

Ulteriori argomenti a parola chiave per Mock() sono impostati come attributi dell'oggetto risultante.

mi mettere le foo e bar definizioni in un modulo my_tests, aggiunto nel HttpError class così ho potuto usarlo troppo, e il test poi può essere eseguito per il successo:

>>> from my_tests import foo, HttpError 
>>> import mock 
>>> with mock.patch('my_tests.bar') as barMock: 
...  barMock.side_effect = HttpError(mock.Mock(status=404), 'not found') 
...  result = my_test.foo() 
... 
404 - 
>>> result is None 
True 

si può anche vedere la print '404 - %s' % error.message line run, ma penso che volevi usare lo error.content lì; questo è l'attributo HttpError() set dal secondo argomento, in ogni caso.

+0

Questo ha fatto il trucco, grazie! –