how do I set return_value of a mocked class instance when I don’t have access to the instance itself?

Suppose I have some function A.foo() that instantiates and uses an instance of B, calling the member function bar on it.

How can I set return_value on a mocked instance of B when I’m testing my A class, given that I don’t have access to the instance of B? Maybe some code would illustrate this better:

import unittest
import unittest.mock
import pandas

class A:
    def foo(self):
        b = B()
        return b.bar()

class B:
    def bar():
        return 1

@unittest.mock.patch("__main__.B")
class MyTestCase(unittest.TestCase):
    def test_case_1(self, MockB):
        
        MockB.bar.return_value = 2
        
        a = A()
        
        self.assertEqual(a.foo(), 2)

test_case = MyTestCase()
test_case.test_case_1()

This fails with;

AssertionError: <MagicMock name='B().bar()' id='140542513129176'> != 2

Apparently the line MockB.bar.return_value = 2 didn’t modify the return value of the method.

Answer

You have just 1 mistake in your code. Replace this line:

MockB.bar.return_value = 2

To:

MockB.return_value.bar.return_value = 2

And it would work.


I assume the piece of code you pasted is just a toy example. If the class A and B lies on another file e.g. src/somedir/somefile.py, don’t forget to patch the full path.

@unittest.mock.patch("src.somedir.somefile.B")
class MyTestCase(unittest.TestCase):
    ...

Update

To further expand on this, you can see some usage in the docs:

>>> class Class:
...     def method(self):
...         pass
...
>>> with patch('__main__.Class') as MockClass:
...     instance = MockClass.return_value
...     instance.method.return_value = 'foo'
...     assert Class() is instance
...     assert Class().method() == 'foo'
...

So in your case:

  • MockB.bar.return_value is like calling a static method e.g. print(MockB.bar())
  • MockB.return_value.bar.return_value is like calling a class/instance method e.g. print(MockB().bar())

To visualize this:

import unittest.mock


class SomeClass:
    def method(self):
        return 1


@unittest.mock.patch("__main__.SomeClass")
def test_mock(mock_class):
    print(mock_class)
    print(mock_class.return_value)

    mock_class.method.return_value = -10
    mock_class.return_value.method.return_value = -20

    print(SomeClass.method())
    print(SomeClass().method())


test_mock()
$ python3 test_src.py 
<MagicMock name='SomeClass' id='140568144584128'>
<MagicMock name='SomeClass()' id='140568144785952'>
-10
-20
  • As you can see, mock_class.return_value is the one used for instance operations such as SomeClass().method().