pytest-dev/pytest-mock

mocker.path create=False argument not working as stated?

noklam opened this issue · 3 comments

Minimal Example

import pytest


class Dummy:
    def __init__(self, x) -> None:
        self.x = x

@pytest.fixture
def mocker_create_true(mocker):
    return mocker.patch(f"{__name__}.Dummy", create=True)


@pytest.fixture
def mocker_create_false(mocker):
    return mocker.patch(f"{__name__}.Dummy", create=False)


def test_mocker_non_exist_attrs_true(mocker_create_true):
    dummy = Dummy(1)
    print(type(dummy), dummy)
    dummy.p


def test_mocker_non_exist_attrs_false(mocker_create_false):
    dummy = Dummy(1)
    with pytest.raises(Exception):
        print(type(dummy), dummy)
        dummy.p

Expected Result

According to the documentation https://docs.python.org/3/library/unittest.mock.html#patch, non-exist attributes access should throw an error when mocker.patch(create=False) is used.

Test Result

================================================================================================ FAILURES =================================================================================================
____________________________________________________________________________________ test_mocker_non_exist_attrs_false ____________________________________________________________________________________

mocker_create_false = <MagicMock name='Dummy' id='140519123293424'>

    def test_mocker_non_exist_attrs_false(mocker_create_false):
        dummy = Dummy(1)
        with pytest.raises(Exception):
            print(type(dummy), dummy)
>           dummy.p
E           Failed: DID NOT RAISE <class 'Exception'>

dummy/tests/test_dummy.py:28: Failed
------------------------------------------------------------------------------------------ Captured stdout call -------------------------------------------------------------------------------------------
<class 'unittest.mock.MagicMock'> <MagicMock name='Dummy()' id='140519123314000'>
========================================================================================= short test summary info =========================================================================================
FAILED dummy/tests/test_dummy.py::test_mocker_non_exist_attrs_false - Failed: DID NOT RAISE <class 'Exception'>
  • a detailed description of the bug or problem you are having
  • output of pip list from the virtual environment you are using
  • pytest and operating system versions
  • minimal example if possible

Versions

pytest 6.2.5
pytest-cov 3.0.0
pytest-forked 1.4.0
pytest-mock 1.13.0
pytest-xdist 2.2.1

Python: 3.8.3 + MacOS

Hi,

Your mocker_create_true is passing create=False, is that a copy/paste error?

Can you check if you get a different behavior if you don't use the mocker fixture, but user unittest.mock directly?

If they behave the same, then it is not a bug, but if they differ, then we should look into it.

@nicoddemus
Thanks, it was a typo, but the failing test is the false one so it is still valid (I have updated the issue now).

I get the same error with unittest.mock.patch, hopefully I am doing it right.

import pytest
from unittest.mock import patch

class Dummy:
    def __init__(self, x) -> None:
        self.x = x

@patch(f"{__name__}.Dummy", create=True)
def test_mocker_non_exist_attrs_true(mock_class):
    dummy = mock_class(1)
    print(__name__)
    print(type(dummy), dummy)
    dummy.p

@patch(f"{__name__}.Dummy", create=False)
def test_mocker_non_exist_attrs_false(mock_class):
    dummy = mock_class(1)
    with pytest.raises(Exception):
        print(type(dummy), dummy)
        dummy.p
------------------------------------------ Captured stdout call -------------------------------------------
<class 'unittest.mock.MagicMock'> <MagicMock name='Dummy()' id='140671590231248'>
========================================= short test summary info =========================================
FAILED dummy/tests/test_dummy.py::test_mocker_non_exist_attrs_false - Failed: DID NOT RAISE <class 'Exce...

If it works the same as unittest.mock then it is working as intended.

I'm not sure create will work as you want, it is meant to create a method if that method doesn't exist, but you are patching the entire class, which does exist (so create has no effect).

I suggest to try autospec=True, but I'm not sure that will work for attributes created during __init__.

Closing for now as this is not related to pytest-mock, but feel free to follow with further questions. 👍