Burlarse de una función para elevar una excepción para probar un bloque excepto


Tengo una función (foo) que llama a otra función (bar). Si invocando bar() se genera un HttpError, quiero manejarlo especialmente si el código de estado es 404, de lo contrario se vuelve a generar.

Estoy tratando de escribir algunas pruebas unitarias alrededor de esta función foo, burlándose de la llamada a bar(). Desafortunadamente, no puedo obtener la llamada burlada a bar() para levantar una Excepción que es atrapada por mi bloque except.

Aquí está mi código que ilustra mi 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()

I seguido de los Mock docs que dicen que debe establecer el side_effect de una instancia Mock a una clase Exception para que la función burlada genere el error.

También miré algunas otras preguntas y respuestas relacionadas con StackOverflow, y parece que estoy haciendo lo mismo que están haciendo para causar que la Excepción sea planteada por su burla.

¿Por qué establecer el side_effect de barMock no causa que se eleve el Exception esperado? Si estoy haciendo algo raro, ¿cómo debería probar la lógica en mi bloque except?

Author: Community, 2015-02-03

1 answers

Su mock está elevando la excepción muy bien, pero falta el valor error.resp.status. En lugar de usar return_value, simplemente diga Mock que status es un atributo:

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

Argumentos de palabra clave adicionales a Mock() se establecen como atributos en el objeto resultante.

Pongo sus definiciones foo y bar en un módulo my_tests, añadido en el HttpError class así que podría usarlo también, y su prueba entonces se puede ejecutar con éxito:

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

Incluso puedes ver la línea print '404 - %s' % error.message correr, pero yo piensa que querías usar error.content allí en su lugar; ese es el atributo HttpError() establece desde el segundo argumento, en cualquier caso.

 74
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-04 19:50:58