8

I am having a hard time mocking an instance of an object.

I would like to write a unit test to test 'my_func' function that uses an instance of a class. I know how to mock class functions, however, I do not know how to mock an instance of the class (object) itself (not a function).

Inside my module file:

# my_module.py

import fancypackage1
import fancypackage2
def my_func():
    x = fancypackage1.SomeClass.somefunction() # I know how to mock this
    myclient = fancypackage2.Client() # I don't know how to mock this
    myresult = do_something(myclient, x) # I know how to mock this
    return myresult

Inside my test file:

# test_my_module.py

import pytest
import mock
import fancypackage1
import fancypackage2
from my_module import my_func    

def test_my_func(mocker):
    mock_someclass_somefunction = mocker.patch('my_module.fancypackage1.SomeClass.somefunction')
    mock_someclass_somefunction.return_value = 'hello'

    mock_client = mocker.patch.object(fancypackage2.Client, '__init__') # TypeError: __init__() should return None, not 'MagicMock'
    mock_do_something = mocker.patch('my_module.do_something')

    my_func()

    mock_do_something.assert_called_with(mock_client, 'hello')
  • Since I did not know how to mock an instance of a class, but I knew how to mock a class method, I figured that perhaps, for the instance of the class, using the constructor function might work - and so I used init, but this did not work for me unfortunately, I am getting an error: E TypeError: __init__() should return None, not 'MagicMock'

  • After the above did not work, I tried passing a custom-made fixture:

      @pytest.fixture
      def client_constructor_mock():
          my_client = fancypackage2.Client()
          return my_client
    
      def test_my_func(mocker, client_constructor_mock):
          mock_someclass_somefunction = mocker.patch('my_module.fancypackage1.SomeClass.somefunction')
          mock_someclass_somefunction.return_value = 'hello'
    
          mock_client = client_constructor_mock
          mock_do_something = mocker.patch('my_module.do_something')
    
          my_func()
    
          mock_do_something.assert_called_with(mock_client, 'hello')
    

Unfortunately, this did not work either. The error I am getting:

    >       mock_do_something.assert_called_with(mock_client, 'hello')
    E       AssertionError: Expected call: do_something(<fancypackage2.Client object at 0x000001E6896A69C8>, 'hello')
    E       Actual call: do_something(<fancypackage2.Client object at 0x000001E689721488>, 'hello')

    

which tells me that there are two different objects of class Client, and that's the error.

I am at a loss here, how do I ensure that myclient is mocked correctly? Any help is very much appreciated.

0

1 Answer 1

5

__init__ cannot be patched directly for manipulating the instances created by the class, as the TypeError suggests. This can be done by patching the class and requesting the return_value of that mock-object, which is the result of calling the __init__ of that class.

Instead of

mock_client = mocker.patch.object(fancypackage2.Client, '__init__') # TypeError: __init__() should return None, not 'MagicMock'

The following should work:

mock_client_class = mocker.patch('my_module.fancypackage2.Client')
mock_client = mock_client_class.return_value
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.