Search code examples
pythonmockingpython-unittestside-effects

Unittest mocked class's method not being called


I'm new to Mock testing. For learning purposes, I'm trying to simulate the status check whether the database connection established or not and no of times the Handler is trying to perform database connect operation.

class Handler:
    
    def is_connected(self):
        # return true if connected to the backend database
        pass

class Backend:

    def initConnection(self):
        handlr = Handler()
        while(True):
            is_connected =  handlr.is_connected()
            print(is_connected)
            if(is_connected):
                break
class TestBackendConnection(TestCase):

    def test_connection_waiting(self):

        """Test that the backend waits for connection untill the handler connects"""
        with patch('side_eff.Handler.is_connected') as isconn:
            bknd = Backend()
            isconn.side_effect = [False] * 4 + [True]

            # print(tryCon()) => False
            # print(tryCon()) => False
            # print(tryCon()) => False
            # print(tryCon()) => False
            # print(tryCon()) => True

            bknd.initConnection()
            self.assertEqual(isconn.call_count, 5)

I'm patching is_connected method of Handler class with side_effect so as to prepare a test case such that for the first four attempts connection is not established and on the fifth attempt connection is established.

Though I mocked the method, the original method is being called.

My Assumption:

On initializing mock behavior to any target, any call made from a newly initialized object to such target mimics the mock behavior defined while patching.


Solution

  • Here is the unit test solution:

    side_eff.py:

    class Handler:
    
        def is_connected(self):
            pass
    
    
    class Backend:
    
        def initConnection(self):
            handlr = Handler()
            while(True):
                is_connected = handlr.is_connected()
                print(is_connected)
                if(is_connected):
                    break
    

    test_side_eff.py:

    import unittest
    from side_eff import Backend
    from unittest.mock import patch
    
    
    class TestBackendConnection(unittest.TestCase):
    
        def test_connection_waiting(self):
            """Test that the backend waits for connection untill the handler connects"""
            with patch('side_eff.Handler') as MockHandler:
                handlerInstance = MockHandler.return_value
                handlerInstance.is_connected.side_effect = [False] * 4 + [True]
                bknd = Backend()
                bknd.initConnection()
                self.assertEqual(handlerInstance.is_connected.call_count, 5)
    
    
    if __name__ == '__main__':
        unittest.main()
    

    Unit test result with coverage report:

    (venv) ☁  python-codelab [master] ⚡  coverage run /Users/ldu020/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/59137518/test_side_eff.py
    False
    False
    False
    False
    True
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.002s
    
    OK
    (venv) ☁  python-codelab [master] ⚡  coverage report -m                                                                                                
    Name                                          Stmts   Miss  Cover   Missing
    ---------------------------------------------------------------------------
    src/stackoverflow/59137518/side_eff.py           11      1    91%   4
    src/stackoverflow/59137518/test_side_eff.py      13      0   100%
    ---------------------------------------------------------------------------
    TOTAL                                            24      1    96%
    

    Source code: https://github.com/mrdulin/python-codelab/tree/master/src/stackoverflow/59137518