Search code examples
pythonmockingpython-unittestreview-board

Mocking ReviewBoard third party library using python and mock


I use ReviewBoard API library and today I moved the code to separate class and wanted to cover the logic with some tests. I understand mocks and testing but I am clearly not much experienced with the python and it's libraries. Here's the chunk of the real code:

<!-- language: python -->
from rbtools.api.client import RBClient

class ReviewBoardWrapper():

    def __init__(self, url, username, password):
        self.url = url
        self.username = username
        self.password = password
        pass

    def Connect(self):
        self.client = RBClient(self.url, username=self.username, password=self.password)
        self.root = self.client.get_root()
        pass

And I want to assert the initialization as well as the get_root() methods are called. Here's how I try to accomplish that:

<!-- language: python -->
import unittest
import mock

from module_base import ReviewBoardWrapper as rb

class RbTestCase(unittest.TestCase):

    @mock.patch('module_base.RBClient')
    @mock.patch('module_base.RBClient.get_root')
    def test_client_connect(self, mock_client, mock_method):
        rb_client = rb('', '', '')
        rb_client.Connect()
        self.assertTrue(mock_method.called)
        self.assertTrue(mock_client.called)

And here's the error I stuck on:

$ python -m unittest module_base_tests
F.
======================================================================
FAIL: test_client_connect (module_base_tests.RbTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "module_base_tests.py", line 21, in test_client_connect
    self.assertTrue(mock_client.called)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.002s

FAILED (failures=1)

What do I do wrong? Do I correctly mock the "local copy" of imported libraries? Does the issue lie completely in a different area?

I have also tried to do this:

@mock.patch('module_base.RBClient.__init__')

And / or this:

self.assertTrue(mock_client.__init__.called)

Solution

  • In the example from your post, the order of the mocking is reversed:

    test_client_connect(self, mock_client, mock_method)
    

    The client is actually being mocked as the second argument and the method call is being mocked as the first argument.

    However, to properly mock the client, you want to mock the return value of the client call. An example of mocking the return value and making an assertion on the return value would like the following:

    class RbTestCase(unittest.TestCase):                                                                                                                                                                        
    
        @mock.patch('module_base.RBClient')                                                                                                                                                                     
        def test_client_connect(self, mock_client):                                                                                                                                                             
            client = mock.MagicMock()                                                                                                                                                                           
            mock_client.return_value = client                                                                                                                                                                   
            rb_client = rb('', '', '')                                                                                                                                                                          
            rb_client.Connect()                                                                                                                                                                                 
            self.assertTrue(client.get_root.called)                                                                                                                                                             
            self.assertTrue(mock_client.called)