Home > Software design >  pytest monkepatch, decorate stub instead of replace
pytest monkepatch, decorate stub instead of replace

Time:12-22

So I have the following example code:

import pytest

class Helper:
    def function1(self):
        print("helper function called")

class SUT:
    def real_function(self):
        helper = Helper()
        helper.function1()
        print("real function called")

def test_Test(monkeypatch):
    test = SUT()
    def stub_function1(self):
        print("helper is stubbed")

    monkeypatch.setattr(Helper, "function1", stub_function1)
    test.real_function()

and running pytest .\test_scratch_1.py --capture=tee-sys prints out helper is stubbed and real function called, as expected.

However, I would actually like to be able print out helper function called before helper is stubbed, thus not fully stubbing the function but rather sort of decorate the function with things to do after it runs. I tried the following:

import pytest

class Helper:
    def function1(self):
        print("helper function called")

class SUT:
    def real_function(self):
        print("real function called")

def test_Test(monkeypatch):
    test = SUT()
    helper_original = Helper()
    def stub_function1(helper_original_not_stubbed):
        helper_original_not_stubbed.function1()
        print("helper is stubbed")

    monkeypatch.setattr(Helper, "function1", stub_function1(helper_original))
    test.real_function()

But this produces the same result. Does anyone know how to achieve this?

CodePudding user response:

You can wrap a decorator around your method prior to calling it.

def my_decorator(function):
    def wrapped_func(*args, **kwargs):
        print("before")
        rt = function(*args, **kwargs)
        print("after")
        return rt
    return wrapped_func

def test_Test():
    test = SUT()
    test.function1 = my_decorator(test.function1)
    test.function1()

CodePudding user response:

So you are actually doing an infinite recursive call with your current solution.

Monkeypatch is to mock a dependency that can be tough to test. So you are misusing it in the above example.

If you wan't something printed before and after then do:

import pytest

class SUT:
    def function1(self):
        print("abc")

def test_Test(monkeypatch):
    test = SUT()
    print("before")
    test.function1()
    print("after")
    
  • Related