Mocking confused with __init__.py module

Issue

I’m currently trying to use mock to test a package. Mock seems to not like it when I structure my python modules in different directories using __init__.py

My file tree is as follows:

.\pkg
  |_ module
       |_ __init__.py
       |_ module.py
  |_ tests
       |_ __init__.py
       |_ test_basic.py

When I try to mock the methods inside filesize using the following unit test:

@mock.patch('module.os')
def test_filesize(self, mock_os):
    class file_info:
        st_size = 1000

    mock_os.path.isfile.return_value = True
    mock_os.stat.return_value = file_info

    output = self.response.file_size("filename")

I get an error with a traceback of:

======================================================================
ERROR: test_filesize (__main__.cl_test_build_search_url)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Python36\lib\site-packages\mock\mock.py", line 1297, in patched
    arg = patching.__enter__()
  File "C:\Python36\lib\site-packages\mock\mock.py", line 1369, in __enter__
    original, local = self.get_original()
  File "C:\Python36\lib\site-packages\mock\mock.py", line 1343, in get_original
    "%s does not have the attribute %r" % (target, name)
AttributeError: <module 'module' from 'C:\\Users\\username\\work\\open_source\\pkg\\module\\__init__.py'> does not have the attribute 'os'

I have imported the os module in module.py but I think it’s getting confused because the __init__.py is confusing the interpreter?

I’ve looked at the mock.patch arguments available and

@mock.patch('module.os', create = True)

allowed the code to run but os doesn’t end up being mocked at all and os.path.isfile and os.stat doesn’t get overridden during run time.

Solution

Try to change this:

@mock.patch('module.os', create = True)

to this:

# module(directory) module(module.py)
@mock.patch('module.module.os', create = True)

I am NOT good at explaining, here is a digest from mock.py explains:

target should be a string in the form 'package.module.ClassName'. The
target is imported and the specified object replaced with the new
object, so the target must be importable from the environment you are
calling patch from. The target is imported when the decorated function
is executed, not at decoration time.

Answered By – Gang

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published