The purpose of patching with mock is to replace the reference to a module as it would be stored in sys.modules
and replace it with a reference to your mock. These means that code in the patched module will receive a reference to the mock object.
In your test, you are working with get_backend
. Which was imported at the top of your test module directly from myapp.models
before the decorator was applied. It is not patched. Your patch is in place, but only for code in myapp.models
which reference the get_backend
symbol imported there.
I know that's confusing. For me it was the hardest part of getting started with mock. If your test looked like this:
class ParsersTest(TestCase):
@patch('myapp.models.get_backend')
def test_simplified(self, moves_backend):
from myapp.models.basic_class import BasicClass
# Assertion should pass
BasicClass.basic_method()
moves_backend.assert_called_with()
moves_backend.return_value = 'new return value'
# As should this one (if you change the method to return instead of print)
self.assertEqual(BasicClass.basic_method(), 'new return value')
I think your test would be passing. The key difference here is that you are not testing against get_backend directly. You are testing a method that uses an imported get_backend after the patch has been applied.
update
The only other thing I can think of, without getting my hands on your actual code, is just that I don't like using patch as a decorator because you get less control over when the patch is applied/removed and worrying about getting a reference to the mock via args.
Try the context manager style:
with mock.patch('my app.models.get_backend') as moves_backend:
#...
with the rest of the test logic nested under that branch.
update part II
I just noticed in your original code that BasicClass
is in myapp.models.basic_class.py
.
If that's the case you patch should be applied to 'myapp.models.basic_class.get_backend'
because you are wanting to patch the reference to get_backend
that is being imported in the myapp.models.basic_class
submodule.