cómo simular una llamada de función utilizada por la biblioteca pypi importada en Python

Tengo el siguiente código que estoy tratando de probar:

gran_informe.py

from retry import retry @retry((ReportNotReadyException), tries=3, delay=10, backoff=3) def get_link(self): report_link = _get_report_link_from_3rd_party(params) if report_link: return report_link else: stats.count("report_not_ready", 1) raise ReportNotReadyException 

Tengo mi función de prueba que simula _get_report_link_from_3rd_party que prueba todo pero no quiero que esta función realmente detenga la ejecución durante la ejecución de las pruebas …

 @mock.patch('repo.great_report._get_report_link_from_3rd_party', return_value=None) test_get_link_raises_exception(self, mock_get_report_link): self.assertRaises(ReportNotReadyException, get_link) 

Intenté burlarme de los parámetros de rebash, pero me estoy topando con problemas en los que get_link sigue reintentando una y otra vez, lo que causa largos tiempos de comstackción en lugar de simplemente elevar la excepción y continuar. ¿Cómo puedo burlarme de los parámetros para la llamada @retry en mi prueba?

No hay forma de cambiar los parámetros de los decoradores después de cargar el módulo. Los decoradores decoran la función original y la cambian en el tiempo de carga del módulo.

Primero me gustaría animarte a que cambies un poco tu diseño para hacerlo más comprobable.

Si extrae el cuerpo del método get_link() prueba el nuevo método y confía en retry decorador obtendrá su objective.

Si no desea agregar un nuevo método a su clase, puede usar un módulo de configuración que almacena las variables que usa cuando el llamador retry decorador. Después de eso puedes usar dos módulos diferentes para pruebas y producción.

La última forma es la forma de pirateo en la que reemplaza retry.api.__retry_internal por una versión que invoque la original cambiando solo las variables:

 import unittest from unittest.mock import * from pd import get_link, ReportNotReadyException import retry orig_retry_internal = retry.api.__retry_internal def _force_retry_params(new_tries=-1, new_delay=0, new_max_delay=None, new_backoff=1, new_jitter=0): def my_retry_internals(f, exceptions, tries, delay, max_delay, backoff, jitter, logger): # call original __retry_internal by new parameters return orig_retry_internal(f, exceptions, tries=new_tries, delay=new_delay, max_delay=new_max_delay, backoff=new_backoff, jitter=new_jitter, logger=logger) return my_retry_internals class MyTestCase(unittest.TestCase): @patch("retry.api.__retry_internal", side_effect=_force_retry_params(new_tries=1)) def test_something(self, m_retry): self.assertRaises(ReportNotReadyException, get_link, None) 

En mi humilde opinión, debe utilizar esa solución de pirateo solo si está con la parte posterior en la pared y no tiene oportunidad de rediseñar su código para hacerlo más comprobable. La función / clase / método interno puede cambiar sin previo aviso y su prueba puede ser difícil de mantener en el futuro .

Como se insinuó aquí , una manera fácil de evitar el sueño real es parcheando la función time.sleep . Aquí está el código que hizo eso por mí:

 @patch('time.sleep', side_effect = lambda _: None)