How to patch an object method in pytest

Viewed 5014

In a class, I have an attribute (self.data) which is a pandas.DataFrame.

I have a method save() in the class that basically calls self.data.to_csv() with some validations beforehand. In the test, I would like to patch this so that it won't actually store data in the directory, I just need to make sure it runs as mock.

I couldn't wrap my head around how to patch it. So far I have:

# Myclass.py

import pandas as pd
class Myclass:
    def __init__(self, data):
        self.data = pd.DataFrame(data=data)

    def save(self, path):
        # Do something validation
        # I would like to patch the line below. 
        self.data.to_csv(path)

In test_myclass.py:

from unittest import mock
import Myclass

@mock.patch(Myclass.to_csv)
def test_save(myclass_fixture):
    myclass_fixture.save(path)

I got the error:

AttributeError: type object 'Portfolio' has no attribute 'to_csv'
1 Answers

to_csv is a method of DataFrame, so you have to patch that method, as it is imported in the production code:

@patch("myproject.Myclass.pd.DataFrame.to_csv")
def test_save(patched_to_csv):
    data = some_test_data  # this may come from a fixture
    my = MyClass(data)
    my.save("some_path")
    patched_to_csv.assert_called_once()

This assumes that your project layout is myproject/Myclass.py.

Note that the first parameter to patch is not an object, but a string, containing the path to the patched object (see where to patch for what it shall contain).

It also looks like you want to take your class from a fixture - in this case you have to add this fixture to the arguments:

@pytest.fixture
def myclass_fixture():
   test_data = ...
   yield MyClass(test_data)

@patch("myproject.Myclass.pd.DataFrame.to_csv")
def test_save(patched_to_csv, myclass_fixture):
    myclass_fixture.save("some_path")
    patched_to_csv.assert_called_once()
Related