简体   繁体   中英

Using unittest.mock's patch in same module, getting “does not have the attribute” when patching via “__main__.imported_obj”

I have what should've been a simple task, and it has stumped me for a while. I am trying to patch an object imported into the current module.

Per the answers to Mock patching from/import statement in Python

I should just be able to patch("__main__.imported_obj") . However, this isn't working for me. Please see my below minimal repro (I am running the tests via pytest ):

Minimal Repro

This is run using Python 3.8.6.

from random import random
from unittest.mock import patch

import pytest

@pytest.fixture
def foo():
    with patch("__main__.random"):
        return

def test(foo) -> None:
    pass

When I run this code using PyCharm, I get an AttributeError :

AttributeError: <module '__main__' from '/Applications/PyCharm.app/Contents/plugins/python/helpers/pycharm/_jb_pytest_runner.py'> does not have the attribute 'random'

Furthermore, when I enter debugger mode in the line before the with patch , I see the attribute __main__ is not defined. I am not sure if it needs to be defined for patch to work its magic.

NOTE: I know I can use patch.object and it becomes much easier. However, I am trying to figure out how to use patch in this question.

Research

Unable to mock open, even when using the example from the documentation

This question is related because it's both a similar error message and use case. Their solution was to use builtins instead of __main__ , but that's because they were trying to patch a built-in function ( open ).

You are assuming that the module the test is running in is __main__ , but that would only be the case if it were called via main . This is usually the case if you are using unittest . With pytest, the tests live in the module they are defined in.

You have to patch the current module, the name of which is accessible via __name__ , instead of assuming a specific module name:

from random import random
from unittest.mock import patch

import pytest

@pytest.fixture
def foo():
    with patch(__name__ + ".random"):
        yield

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM