0

I have the following directory structure:

├── project
│   ├── modules
│   │   ├── __init__.py.py
│   │   ├── module.py
│   ├── main.py
├── tests
│   ├── test_main.py

where module.py is:

class My_Class(object):
    def __init__(self):
        raise Exception("This is a test exception")

and main.py is:

import asyncio

from modules.module import My_Class

async def main():
    my_class = My_Class()

if __name__ == "__main__":
    asyncio.run(main())

I am trying to write test_main.py such that My_Class() is patched so that the exception is not raised when running the test.

This is what I have now:

import pytest
from unittest.mock import patch

from project.main import main

@pytest.mark.asyncio
@patch("project.modules.module.My_Class")
async def test_main(mock_my_class):
    await main()

But I'm hitting this import error:

ImportError while importing test module 'C:\Users\me\OneDrive\Desktop\deleteme\tests\test_main.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\importlib\__init__.py:126: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
tests\test_main.py:4: in <module>
    from project.main import main
project\main.py:3: in <module>
    from modules.module import My_Class
E   ModuleNotFoundError: No module named 'modules'
Locks
  • 61
  • 6

2 Answers2

0

You need to add an empty __int__.py file to the directories you want to treat as modules. Here's a great SO answer for what that is and why it's needed: https://stackoverflow.com/a/448279/190902

hookedonwinter
  • 12,436
  • 19
  • 61
  • 74
  • Thank you I forgot that in this example, but that doesn't solve the error that I'm getting. main.py ran successfully and properly imported the module without __init__.py as well. – Locks Jun 15 '23 at 22:44
0

I found that I had to add the project directory to my path. As well, I had to modify the patch statement. Based on the mock documentation on "where to patch" here, the class needs to be patched where it is being used, so in my case that is project.main.My_Class not project.modules.module.My_Class.

import os
import sys

import pytest
from unittest.mock import patch

Parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
project_dir = os.path.join(Parent_dir, 'project')
sys.path.insert(0, project_dir)

from project.main import main

@pytest.mark.asyncio
@patch("project.main.My_Class")
async def test_main(mock_my_class):
    await main()
Locks
  • 61
  • 6