Deridere una funzione per sollevare un'eccezione per testare un blocco eccetto


119

Ho una funzione ( foo) che chiama un'altra funzione ( bar). Se invocare bar()solleva un HttpError, voglio gestirlo specialmente se il codice di stato è 404, altrimenti rilancia di nuovo.

Sto cercando di scrivere alcuni unit test attorno a questa foofunzione, deridendo la chiamata a bar(). Sfortunatamente, non riesco a ottenere la chiamata derisa a bar()per sollevare un'eccezione che viene catturata dal mio exceptblocco.

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 i documenti Mock che dicono che dovresti impostare il side_effectdi Mockun'istanza su una Exceptionclasse per fare in modo che la funzione derisa sollevi l'errore.

Ho anche esaminato alcune altre domande e risposte relative a StackOverflow, e sembra che io stia facendo la stessa cosa che stanno facendo per causare ed Eccezione per essere sollevata dalla loro simulazione.

Perché l'impostazione side_effectdi barMocknon provoca l'aumento del previsto Exception? Se sto facendo qualcosa di strano, come devo fare per testare la logica nel mio exceptblocco?


Sono abbastanza sicuro che la tua eccezione sia stata sollevata, ma non sono sicuro di come stai impostando il resp.statuscodice lì. Da dove HTTPErrorviene?
Martijn Pieters

@MartijnPieters HttpErrorè una classe definita in di Google apiclientlib che usiamo in GAE. È __init__definito con i parametri, (resp, content)quindi stavo tentando di creare un'istanza fittizia per la risposta, con il codice di stato appropriato specificato.
Jesse Webb

Bene, quindi è questa classe ; ma non è necessario che l'utente return_valueutilizzi; respnon viene chiamato .
Martijn Pieters

1
Ho provato di nuovo il mio codice senza utilizzare HttpErrore invece ho provato a utilizzare solo Exceptionun'istanza normale . Funziona perfettamente. Ciò significa che deve avere qualcosa a che fare con il modo in cui sto configurando l' HttpErroristanza, probabilmente correlato a come sto creando Mockun'istanza per la risposta.
Jesse Webb

Risposte:


141

La tua simulazione solleva l'eccezione senza problemi, ma error.resp.statusmanca il valore. Piuttosto che usare return_value, dì semplicemente Mockche statusè un attributo:

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

Argomenti di parole chiave aggiuntivi da Mock()impostare come attributi sull'oggetto risultante.

Ho inserito le tue definizioni fooe barin un my_testsmodulo, aggiunto nella HttpErrorclasse in modo da poterlo usare anch'io, e il tuo test può essere eseguito con 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

Puoi anche vedere la print '404 - %s' % error.messagelinea che scorre, ma penso che volessi usarla error.contentinvece; questo è il HttpError()set di attributi dal secondo argomento, in ogni caso.


2
questa side_effectè la parte fondamentale
Daniel Butler
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.