Search code examples
pythonpython-unittestpython-mock

mocking a return of class object method in python


I would like to mock a method to return a test value in one of my mocked classes. The issue I am running into is rather then returning the test value, the mocked method returns an object of type MagicMock.

The code is pretty contrived but illustrates the issue.

SuT (sut.py):

provider = None


class Provider():
    def get_data(self):
        return 'production data'


def get_provider():
    return Provider()


def setup_provider():
    global provider
    provider = get_provider()


def do_worker():
    return provider.get_data()

Test (mocking.py):

import unittest
from mock import MagicMock
import sut


class TestWorker(unittest.TestCase):
    def test_worker(self):
        provider_mock = MagicMock()
        provider_mock.get_data.return_value = 'test data'

        sut.get_provider = MagicMock(name='get_provider').return_value = provider_mock

        sut.setup_provider()

        data = sut.do_worker()

        # data comes back as type MagicMock
        assert data == 'test data'

Solution

  • You got confused by your chained assignment:

    sut.get_provider = MagicMock(name='get_provider').return_value = provider_mock
    

    That assignment binds provider_mock to both sut.get_provider and to MagicMock(name='get_provider').return_value.

    In other words, it essentially does this:

    sut.get_provider = provider_mock
    MagicMock(name='get_provider').return_value = provider_mock
    

    That's not what you wanted. Now sut.get_provider calls provider_mock and returns a new MagicMock object, not the original provider_mock object.

    Separate the assignments:

    sut.get_provider = MagicMock(name='get_provider')
    sut.get_provider.return_value = provider_mock