简体   繁体   中英

Mocking a function call of a class instance which is a member of another class instance in Python

I am using Python2.7 and modules unittest and mock for this version. I have a situation where I'd like to mock a function call of an instance of a class and its return value. The trouble is, this instance is a member of an instance of a different class. Let me clarify in code.

Let's say I have a class Bin defined in my_package/bin.py :

class Bin():
    def __init__(self):
        # code to initialize other stuff
        self.rubbish = self.fill_with_rubbish()  # creates list of rubbish instances

    def inspect_rubbish(self):
        inspection_results = []
        for rubbish in self.rubbish:
            inspection_results.append(rubbish.inspect())

I also have class Rubbish defined in my_package/rubbish.py :

class Rubbish():
    def __init__(self):
        # initialization stuff

    def inspect(self):
        return 'Nice rubbish'   

Now, in my /tests folder I have a test file test_bin.py where I set up the environment and import the bin and rubbish as follows:

import my_package.bin as _bin
import my_package.rubbish as _rubbish

and I am trying to test the inspect_rubbish() of the Bin class. The above is, obivously, not my production code, but in my original code I'd like to be able to modify the retun value of inspect of the Rubbish isntance and do various assert calls on it to check for how many times it has been called and so on.

I have been sort of stuck on how to actually mock the methods of the Rubbish instances of the Bin instance. I have tried to tackle the problem with some patching but to no avail.

def test_inspect_rubbish(self):
    with patch('my_package.bin.Bin', autospec=True) as mock_bin, \
        patch.object('my_package.rubbish.Rubbish.inspect') as mock_inspect:

        mock_inspect.return_value = 'Bad rubbish'

        bin = _bin.Bin()
        bin.rubbish = [MagicMock(), MagicMock()]
        result = bin.inspect_rubbish()

        mock_inspect.assert_called()

But this code fails with AssertionError: Expected 'inspect' to have been called. so I guess it is not doing what I intend it to at all. How would I go about mocking this behaviour and doing assertions on it afterwards?

  1. Because you mocked Bin , bin.inspect_rubbish() is a mock call which doesn't do anything.
  2. bin.rubbish = [MagicMock(), MagicMock()] means that the mocked Rubbish.inspect is never called, only MagicMock().inspect for each of those mocks.

This code works:

def test_inspect_rubbish(self):
    with patch('my_package.rubbish.Rubbish.inspect') as mock_inspect:

        mock_inspect.return_value = 'Bad rubbish'

        bin = _bin.Bin()
        bin.rubbish = [_rubbish.Rubbish(), _rubbish.Rubbish()]
        result = bin.inspect_rubbish()

        mock_inspect.assert_called()

Demo: https://repl.it/repls/RundownTastyKernel

I also changed patch.object to just patch because that gave an error.

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