0

Hi I am trying to test to see if a method in object A calls another object, object B's, methods. I already have separate tests which tests B's functionality so my goal is just to see if B's method has been called. I am trying to use mocks to create a mock object B, following a method similar to this, but keep getting the following error: AssertionError: Expected 'process' to have been called once. Called 0 times. Am I doing the mock wrong?

From my understanding, this answer suggested to access the field in sut and set it to a mock, but due to how my code is setup I can not access the other objects.

Example code:

# object B
from abc import ABCMeta


class B(metaclass=ABCMeta):
    def process(self):
        print('I am B')
# object C
from abc import ABCMeta


class C(metaclass=ABCMeta):
    def process(self):
        print('I am C')
# object A
from abc import ABCMeta

from b import B
from c import C


class A(metaclass=ABCMeta):
    def __init__(self):
        self.__known_auto_processes = {}
        self.__inti_know_processes()

    def process(self, arg):
        try:
            self.__known_auto_processes[arg].process()
        except KeyError as error:
            print(f'Invalid arg option {error.args}.')

    def __inti_know_processes(self):
        self.__known_auto_processes['B'] = B()
        self.__known_auto_processes['C'] = C()

Example Test:

import unittest
from unittest.mock import patch

from a import A


class TestA(unittest.TestCase):
    @patch("b.B")
    def test_b_call(self, mock_b):
        a = A()
        a.process('B')
        mock_b.process.assert_called_once()
alyacode
  • 11
  • 1
  • You patch where things are _used_, not where they're _defined_ - this is called out _specifically_ [in the docs](https://docs.python.org/3/library/unittest.mock.html#where-to-patch). – jonrsharpe Aug 15 '22 at 19:23

1 Answers1

1

These posts helped me link1 link2. Something like this should work. I think what this does is it creates a mock wrapper around the process in B, as a result, it will count the times it is called.

If you have more insight or a better explanation that would be appreciated.

import unittest
from unittest.mock import patch, PropertyMock

from a import A
from b import B


class TestA(unittest.TestCase):
    @patch.object(B, 'process', new_callable=PropertyMock)
    def test_b_call(self, mock_b):
        a = A()
        mock_b.return_value = mock_b.process
        a.process('B')
        mock_b.process.assert_called_once()

You can also add something like mock_obj.process.return_value = (mock.MagicMock(), mock.MagicMock()) if you code expects something to be returned, in my actual code it expected 2 arguments.

alyacode
  • 11
  • 1