2

I am trying to mock a class which is called in a module which imports said class, which I want to test.

# application.py
from my_module.my_submodule import MyClass

def my_function(var1):
    instance = MyClass()

    instance.some_function(var1)

and my testing file

# test_application.py
import mock
import application

def test_my_function():
    with mock.patch('my_module.my_submodule.MyClass') as MockClass:
        application.my_function(var1)

        MockClass.assert_called()        

This gives an error saying MockClass was not called.

Now, by looking at this question: Why python mock patch doesn't work?, I was inspired to change the application.py import to this

# application.py
import my_module.my_submodule as mysub

def my_function(var1):
    instance = mysub.MyClass()

    instance.some_function(var1)

that is, I don't directly import the class that I want to mock in the test. Now it works.

My question is, if this is working as intended, or I am doing something wrong in the original way? Is it really necessary to always import modules like this, if I want to mock a class used in a module I want to test?

Kaspar H
  • 179
  • 4
  • 10

1 Answers1

6

Yes it is working as intended, but you patched the wrong target. Try patching application.MyClass.

application is not using my_module.my_submodule.MyClass anywhere, but MyClass alias instead.

No, you don't have to import modules in some specific way to be able to mock/patch some name. What you have to do is to look at how that name is used at runtime, when you want it patched.

If the test is in a separate module from the module being tested, and the tested module, application in this case, imports the name and uses it directly like in from a import MyClass, then in the test module you import application and patch application.MyClass. If instead application uses import a and then calls a.MyClass() you have to patch application.a.MyClass.

So you adapt the patch target to the concrete naming scenario in the application module. For example if your test is in the same application module, and the class is being used as MyClass, you need to patch __main__.MyClass.

It is however true, that writing code in certain ways can make it easier to patch when you are testing. A good example is when the entity to mock is a function parameter. Just call the function with a mock argument.

If you find that patching is too convoluted or looks impossible, try to rewrite the code in the application so that it is more "testable".

For another example as reference, see Where to patch

progmatico
  • 4,714
  • 1
  • 16
  • 27
  • Thanks, I had a similar problem and could not figure out why I am not able to mock my class `application.MyClass` helps :) –  May 27 '21 at 11:27