olivierr91
olivierr91

Reputation: 1415

Unable to patch class instantiated by the tested class using unittest

I am trying to patch a class that is instantiated by the class I am trying to test, but it doesn't work. I have read the various docs but still haven't found what I am doing wrong. Here is the code snippet:

In tests/Test.py:

from module.ClassToTest import ClassToTest

class Test(object):

    @mock.patch('module.ClassToPatch.ClassToPatch', autospec = False)
    def setUp(self, my_class_mock):
        self.instance = my_class_mock.return_value
        self.instance.my_method.return_value = "def"
        self.class_to_test = ClassToTest()

    def test(self):
        val = self.class_to_test.instance.my_method() #Returns 'abc' instead of 'def'
        self.assertEqual(val, 'def')

In module/ClassToPatch.py:

class ClassToPatch(object):
    def __init__(self):
        pass
    def my_method(self):
        return "abc"

In module/ClassToTest.py:

from module.ClassToPatch import ClassToPatch

class ClassToTest(object):
    def __init__:
        # Still instantiates the concrete class instead of the mock
        self.instance = ClassToPatch()

I know in this case I could easily inject the dependency, but this is just an example. Also, we use a single class per file policy, with the file named like the class, hence the weird import naming.

Upvotes: 8

Views: 2100

Answers (1)

Ethan Furman
Ethan Furman

Reputation: 69021

As norbert mentions, the fix is to change the mock line from

@mock.patch('module.ClassToPatch.ClassToPatch', autospec = False)

to

@mock.patch('module.ClassToTest.ClassToPatch', autospec = False)

According to the docs:

The patch() decorator / context manager makes it easy to mock classes or objects in a module under test. The object you specify will be replaced with a mock (or other object) during the test and restored when the test ends.

You are testing the ClassToTest module, not the ClassToPatch module.

Upvotes: 5

Related Questions