pytest: monkeypatch while using hypothesis

1.3k Views Asked by At

Within a unit test, I'm using monkeypatch in order to change entries in a dict.

from hypothesis import given, strategies
    
    
test_dict = {"first": "text1", "second": "text2"}
    
    
given(val=strategies.text())
def test_monkeypath(monkeypatch, val):
    monkeypatch.setitem(test_dict, "second", val)
    
    assert isinstance(test_dict["second"], str)

The test passes, but I get a warning when executing the following test code with pytest.

=================================================================================================================== warnings summary ====================================================================================================================
.PyCharm2019.2/config/scratches/hypothesis_monkeypatch.py::test_monkeypath
  c:\users\d292498\appdata\local\conda\conda\envs\pybt\lib\site-packages\hypothesis\extra\pytestplugin.py:172: HypothesisDeprecationWarning: .PyCharm2019.2/config/scratches/hypothesis_monkeypatch.py::test_monkeypath uses the 'monkeypatch' fixture, wh
ich is reset between function calls but not between test cases generated by `@given(...)`.  You can change it to a module- or session-scoped fixture if it is safe to reuse; if not we recommend using a context manager inside your test function.  See h
ttps://docs.pytest.org/en/latest/fixture.html#sharing-test-data for details on fixture scope.
    note_deprecation(

-- Docs: https://docs.pytest.org/en/stable/warnings.html
============================================================================================================= 1 passed, 1 warning in 0.30s ==============================================================================================================

Does this mean that the value of the dict will only be changed once, no matter how many test cases will be generated by hypothesis?
I am not sure how to use a context manager in this case. Can somebody please point me in the right direction?

2

There are 2 best solutions below

2
On BEST ANSWER

Your problem is that the dict is patched only once for all test invocations, and Hypothesis is warning you about that. If you had any logic before the monkeypatch.setitem line, this would be very bad!

You can work around this by using monkeypatch directly, instead of via a fixture:

from hypothesis import given, strategies
from _pytest.monkeypatch import MonkeyPatch


test_dict = {"first": "text1", "second": "text2"}


@given(val=strategies.text())
def test_monkeypath(val):
    assert test_dict["second"] == "text2"  # this would fail in your version

    with MonkeyPatch().context() as mp:
        mp.setitem(test_dict, "second", val)
        assert test_dict["second"] == val

    assert test_dict["second"] == "text2"

et voila, no warning.

1
On

Use the monkeypatch context manager

@given(val=strategies.text())
def test_monkeypath(monkeypatch, val):
    with monkeypatch.context() as m:
        m.setitem(test_dict, "second", val)

        assert isinstance(test_dict["second"], str)