How to correctly use pytest mocker to patch a function?

What is the correct way to use pytest mocker to patch a function?

I have installed pytest-mock and am trying to use the mocker fixture to patch a function, but I am getting the error "TypeError: Need a valid target to patch. You supplied 'return a + b'".

Here is the code I am working with:

# test_capitalize.py
import time

def sum(a, b):
    time.sleep(10)
    return a + b

def test_sum(mocker):
    mocker.patch('return a + b')  # This is where I get the error
    assertEqual(sum(2, 3), 9)

Can you help me understand how to correctly use pytest mocker to patch the sum function and avoid this error?

I’ve worked with pytest mocker quite a bit, and the key to using it correctly is ensuring you’re patching the right function with the correct path. Here’s a simple example of patching with return_value to override a function’s output:

:small_blue_diamond: Patching with a return_value to Simulate a Fixed Result:

You can make a function return a fixed value, regardless of its input:

import pytest

def sum(a, b):
    return a + b

def test_sum1(mocker):
    mocker.patch(__name__ + ".sum", return_value=9)
    assert sum(2, 3) == 9  # This will pass because 'sum' always returns 9 now

Here, pytest mocker ensures sum() always returns 9, making the test predictable.

@joe-elmoufak nailed the basics! But sometimes, you need more flexibility than a fixed return value. That’s where side_effect comes in.

:small_blue_diamond: Patching with a side_effect to Change Function Behavior Dynamically:

Instead of returning a fixed value, you can provide a custom function to control behavior:

def test_sum2(mocker):
    def crazy_sum(a, b):
        return b + b  # A different behavior, summing only 'b'

    mocker.patch(__name__ + ".sum", side_effect=crazy_sum)
    assert sum(2, 3) == 6  # This will pass because the new behavior sums 'b + b'

Now, pytest mocker replaces sum() with crazy_sum(), changing the behavior dynamically. Super useful for simulating complex logic!

Great points so far! But what if you’re testing code that interacts with an external API or service? You don’t want tests to depend on real API calls, so let’s patch an external function instead.

:small_blue_diamond: Using pytest mocker to Patch an External Function (for APIs & Services):

import requests
import pytest

def get_weather(city):
    response = requests.get(f"https://api.weather.com/{city}")
    return response.json()

def test_weather(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"temperature": 72}
    
    # Patching 'requests.get' to return our mock response
    mocker.patch('requests.get', return_value=mock_response)

    weather = get_weather("New York")
    assert weather["temperature"] == 72  # Test runs without hitting the actual API

This is a lifesaver when dealing with APIs. pytest mocker ensures your tests are isolated and fast!