pytest monkepatch, decorate stub instead of replace

Question:

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?

Asked By: aldo

||

Answers:

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")
    
Answered By: enslaved_programmer

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()
Answered By: Marcel Wilson
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.