how to mock function call used by imported pypi library in python

前端 未结 2 1440
误落风尘
误落风尘 2020-12-12 04:47

I have the following code that I\'m trying to test:

great_report.py

from retry import retry

@retry((ReportNotReadyException), tries=3, delay=10, bac         


        
相关标签:
2条回答
  • 2020-12-12 05:21

    There is no way to change decorators parameters after load the module. Decorators decorate the original function and change it at the module load time.

    First I would like encourage you to change your design a little to make it more testable.

    If you extract the body of get_link() method test the new method and trust retry decorator you will obtain your goal.

    If you don't want add a new method to your class you can use a config module that store variables that you use when call retry decorator. After that you can use two different module for testing and production.

    The last way is the hacking way where you replace retry.api.__retry_internal by a your version that invoke the original one by changing just the 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)
    

    IMHO you should use that hacking solution only if you are with the back on the wall and you have no chance to redesign you code to make it more testable. The internal function/class/method can change without notice and your test can be difficult to maintain in the future.

    0 讨论(0)
  • 2020-12-12 05:27

    As hinted here, an easy way to prevent the actual sleeping is by patching the time.sleep function. Here is the code that did that for me:

    @patch('time.sleep', side_effect = lambda _: None)
    
    0 讨论(0)
提交回复
热议问题