11

All,

I have a class similar to this.

from mod import Bar

class Foo:
  def __init__(self):
    self.obj = Bar()

How do I mock the Bar constructor using pytest / pytest-mock? I have tried the following unsuccessfully.

def test():
  with mock.patch('mod.Bar') as patched:
    Foo()
5
  • Possible duplicate of Mock attributes in Python mock? Commented Jul 15, 2019 at 15:11
  • @ConstantinGuidon I've included details from that post now. It is not working for me. Commented Jul 15, 2019 at 15:30
  • 1
    You have to patch "yourmodule.Bar" instead of "mod.Bar". See docs.python.org/3/library/unittest.mock.html#where-to-patch for details. Commented Jul 15, 2019 at 15:32
  • @AlexanderFasching If you post an answer, I'll edit it an mark it as correct. Commented Jul 15, 2019 at 15:40
  • @AlexanderFasching How would one integrate this into an @pytest.fixture Commented Jul 15, 2019 at 15:54

2 Answers 2

6

You have to patch the name, not the instance.

From the official Python documentation: Where to patch

patch() works by (temporarily) changing the object that a name points to with another one. There can be many names pointing to any individual object, so for patching to work you must ensure that you patch the name used by the system under test.

In your example, your class Foo is defined in a module foomod.py, so you have to patch foomod.Bar instead of mod.Bar.

You can put this into a fixture by using the mocker fixture from pytest-mock or with unittest.mock.patch.

@pytest.fixture # With pytest-mock
def mock_bar(mocker):
    return mocker.patch('foomod.Bar')

@pytest.fixture # With stdlib
def mock_bar():
    with patch('foomod.Bar') as mock:
        yield mock

# Usage
def test_foo(mock_bar):
    pass

To my knowledge, there is no significant difference between the two approaches. Both are cleaned up when the fixture goes out of scope.

Sign up to request clarification or add additional context in comments.

Comments

1

I use the following to mock objects with pytest without the fixture decorator

# path.to.MyClass
class MyClass():
    def __init__(self, some_parameter: SomeObject) -> None:
        self.some_value = some_parameter

    def get_something(self) -> str:
        return 'Hello'


# tests.py
from pytest_mock.plugin import MockerFixture
from unittest.mock import MagicMock

def test_with_mock(mocker: MockerFixture) -> None:
    mock_myclass: MagicMock = mocker.patch('path.to.MyClass')

    mock_myclass_get_something: MagicMock = mocker.patch('path.to.MyClass.get_something')
    mock_myclass_get_something.return_value = 'World!'

    assert mock_myclass.get_something() == 'World!'

1 Comment

How to mock the some_value?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.