Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 515
olivierr91 Avatar asked Feb 23 '16 20:02

olivierr91


People also ask

What is Patch in Unittest?

unittest. mock provides a powerful mechanism for mocking objects, called patch() , which looks up an object in a given module and replaces that object with a Mock . Usually, you use patch() as a decorator or a context manager to provide a scope in which you will mock the target object.

What is unittest mock?

unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. unittest.mock provides a core Mock class removing the need to create a host of stubs throughout your test suite.

What is mocking in Pytest?

In pytest , mocking can replace the return value of a function within a function. This is useful for testing the desired function and replacing the return value of a nested function within that desired function we are testing.


1 Answers

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.

like image 100
Ethan Furman Avatar answered Oct 01 '22 19:10

Ethan Furman