Search code examples
python-3.xunit-testingmocking

Python mock Path object inside function with path input argument as string


I want to test a code I wrote which read a file and save in a pandas dataframe.

the code is:

# utilities/reading_files.py

def read_data_file(file_path):
    """Function to read the data file.

    This function can read a .chi, .txt, and a .xy file.

    Args:
        file_path: path of the data file

    Returns:
        df: dataframe with transfer momentum and intensity or an empty
            dataframe
    """

    data_file = Path(file_path)

    if not data_file.is_file():
        LOGGER.error("The file does not exist! Try with another file.")
        return pd.DataFrame()

    file_suffix = data_file.suffix

    if file_suffix not in SUPPORTED_DATA_FORMAT:
        LOGGER.error(
            "The file format is not recognised! "
            "The supported formats are: .chi, .txt, .xy."
        )
        return pd.DataFrame()

    if file_suffix == ".chi":
        skipped_rows = 4
    elif file_suffix == ".xy":
        skipped_rows = 17
    else:
        skipped_rows = 0

    df = pd.read_csv(
        data_file, sep=" ", header=None, skiprows=skipped_rows
    ).dropna(axis="columns", how="all")

    if df.columns.size != 2:
        LOGGER.error(
            f"The file must contain just two columns with Q and I(Q). "
            f"The file contains {df.columns.size} columns."
        )
        return pd.DataFrame()

    df.columns = ["q", "i_q"]

    return df

I have problems to understand how to mock the file exists, as I don't want to create fake files for the test.

I started with something like this to test that, an existing file doesn't have the supported extension:

from unittest.mock import patch
from pathlib import Path

import utilities.reading_files as rf

def test_data_file_format(caplog):
    """Test the data file extension is supported."""

    mock_path = Path("./data.dat")
    with patch.object(Path, "is_file") as mock_is_file:
        mock_is_file.return_value = True
        df = rf.read_data_file(XXXXXXX)

    assert df.empty
    assert caplog.messages[0] == (
        "The file format is not recognised! "
        "The supported formats are: .chi, .txt, .xy."
    )

I don't know what to give as input of my function.

I could give mock_path, but it doesn't feel right as it's not a string, or it is the right thing to do?

Any advice?


Solution

  • I managed to test the function following this answer https://stackoverflow.com/a/56023615/5423080

    This is my code:

    @mock.patch("utilities.reading_files.Path")
    def test_data_file_extension(path_mocking, caplog):
        """Test if an existing data file has right extension."""
        mock_path = mock.MagicMock()
        path_mocking.return_value = mock_path
        mock_path.is_file.return_value = True
    
        df = rf.read_data_file("./data.dat")
    
        assert df.empty
        assert caplog.messages[0] == (
            "The file format is not recognised! "
            "The supported formats are: .chi, .txt, .xy."
        )