简体   繁体   中英

How to mock an instance method in Python

I'm trying to test a class and mock one of its methods, but I can't seem to replace the behavior of one of the instance methods with my mocked behavior. My code is organized like so:

--src ----module ------__init__.py ------my_class.py --tst ----__init__.py ----test_my_class.py

my_class.py contains the following

class MyClass:

    def __init__(self):
        pass

    def do_something(self):
        return 'Real Output'

My test file test_my_class.py contains the following.

from unittest.mock import patch
from src.module.my_class import MyClass

def test_my_class():
    my_class = MyClass()
    assert my_class.do_something() == 'Real Output'

@patch('src.module.my_class.MyClass')
def test_mock_my_class(mock_my_class):
    mock_my_class.return_value.do_something.return_value = 'Mocked Output'
    my_class = MyClass()
    assert my_class.do_something() == 'Mocked Output'

The first test works just fine (no mocking involved so far). The second test, however, gives me the following assertion error. I expect the do_something() method to be mocked and to return "Mocked Output", and for the assert statement to evaluate to true. Where am I going wrong here?

AssertionError: assert <bound method MyClass.do_something of <src.module.my_class.MyClass object at 0x1057133c8>> == 'Mocked Output' E + where <bound method MyClass.do_something of <src.module.my_class.MyClass object at 0x1057133c8>> = <src.module.my_class.MyClass object at 0x1057133c8>.do_something

PS. I've consulted the following resources without success:

That last link looked especially helpful at first, because I'm following one of the examples almost verbatim, but it still doesn't work.

@mock.patch("simple.SimpleClass")
def mock_simple_class(mock_class):
    mock_class.return_value.explode.return_value = "BOO!"
    inst = simple.SimpleClass()
    result = inst.explode()
    print(result)

A more appropriate way to solve this is to use patch.object

@patch.object(MyClass, "do_something")
def test_mock_my_class(m):
    m.side_effect = ['Mocked Output']
    my_class = MyClass()
    assert my_class.do_something() == 'Mocked Output'

Personally, patch.object confuses me. After reading this article , I have decided to stick with patch only.

The problem with the patch in the question is that the MyClass patched is not the MyClass used in the test function. Refer to this guide for a more in-depth explanation of where patch should be applied.

The path of the patch should be tst.test_my_class.MyClass , as shown in the code below.

from unittest.mock import patch
import unittest
from src.module.my_class import MyClass


class Test(unittest.TestCase):
    def test_my_class(self):
        my_class = MyClass()
        self.assertTrue(my_class.do_something() == 'Real Output')

    @patch('test.test_my_class.MyClass')
    def test_mock_my_class(self, mock_my_class):
        mock_my_class.return_value.do_something.return_value = 'Mocked Output'
        my_class = MyClass()
        self.assertTrue(my_class.do_something() == 'Mocked Output')

Run this command to execute it in a terminal.

python3 -m unittest discover

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM