Search code examples
pythonunit-testingmodulemockingpytest

Mocking directly imported function?


I am trying to write unit tests for my python project using pytest. I have a module from another repo called sql_services. Within sql_services there is a function called read_sql that I am trying to mock.

So far, I have only been able to mock the function if I import the module like

import sql_services

and invoke sql_services.read_sql but I have been unable to mock it if I import the function like

from sql_services import read_sql

This is a problem because my codebase uses the latter method for importing the functions

Here is the function I am trying to write a unit test for:

from sql_services import read_sql

def foo():
    df = read_sql("SELECT * FROM schema.table")
    return df

Here is the unit test file I have so far:

import pytest
import unittest.mock as mock
import pandas as pd

import sql_services

from entry import foo

@mock.patch("sql_services.read_sql")
def test_read_sql(mock_read_sql):
    mock_read_sql.return_value = pd.DataFrame()
    df = sql_services.read_sql("SELECT * FROM schema.table")
    assert df.empty

@mock.patch("sql_services.read_sql")
def test_do_a_read(mock_read_sql):
    mock_read_sql.return_value = pd.DataFrame()
    df = foo()

    assert df.empty

The first test passes and the second fails because it actually reads the data frame from the database. Is there any way I can mock the function from within foo without refactoring my entire codebase?


Solution

  • You just patch the correct name:

    @mock.patch("entry.read_sql")
    def test_read_sql(mock_read_sql):
        mock_read_sql.return_value = pd.DataFrame()
        df = sql_services.read_sql("SELECT * FROM schema.table")
        assert df.empty]
    

    entry.foo is using the global variable entry.read_sql to access the function you want to mock, not the global variable sql_servies.read_sql.