Search code examples
pythonpython-3.6pytestfixturesmonkeypatching

How to patch function inside a parametrized fixture?


I would like to patch a function depending of the environment thus considering we have environnement mode1 and mode2 .

With the code below monkeypatch call always the function patched from mode1

If I switch the param order mode2 and mode1 it will call always the function patched from mode2.

But I would like to use the function pacthed dependeing of the requested param.

I checked using the debugger both condtion checking the mode: mode1 and mode2 works and set as expected the right function. But allways it keep the first function patched.

conftest.py

def pytest_generate_tests(metafunc):
  if 'patch_fhs' in metafunc.fixturenames:
    metafunc.parametrize('patch_fhs', ['mode1', 'mode2'], indirect=True, scope='session')


@pytest.fixture()
def parametrized_patch(request):
  if request.param == 'mode1':
    monkeypatch = MonkeyPatch()
    import mymodule
    def patched_func():
      return 'patched_mode1'
    monkeypatch.setattr(mymodule, 'my_func', patched_func)
  elif if request.param == 'mode2':
    monkeypatch = MonkeyPatch()
    import mymodule
    def patched_func():
      return 'patched_mode2'
    monkeypatch.setattr(mymodule, 'my_func', patched_func)
  else:
    raise ValueError('Unknown mode named: {name}'.format(name=request.param))
  return request.param

test_parametrized_fixture.py

def test_foo(parametrized_patch):
 from mymodule import my_func
 print(parametrized_patch)
 print(my_func)

The tests ouptput will be something like

-> test_foo
mode1
patched_mode1
-> test_foo
mode2
patched_mode1

Solution

  • Try this:

    @pytest.fixture(params=your_params)
    def parametrized_patch(monkeypatch, request):
        monkey patch.setattr(
            your_module,
            'your_func',
            lambda x, y, z: request.param
        )
    

    x, y, z are the arguments the function you are trying to patch will take