Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pytest - Mocking constructor within constructor

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()
like image 832
Dan Grahn Avatar asked Jul 15 '19 15:07

Dan Grahn


2 Answers

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.

like image 62
Alexander Fasching Avatar answered Nov 13 '22 09:11

Alexander Fasching


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!'
like image 42
Dev Sareno Avatar answered Nov 13 '22 08:11

Dev Sareno