Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: patching function defined in same module of tested function

I have been working with Python's unittest.mock library quite a bit, but right now I'm struggling with a use case that may not be approached correctly.

Consider a file mymodule/code.py containing the following snippet:

def sum():
  pass

def mul():
  pass

def div():
  pass

def get_functions():
  return [sum, mul, div]

def foo():
  functions = get_functions()
  for func in functions:
    func()

I want to test the foo function, patching the sum function, and leaving mul and div as they are. This is what I tried initially:

class TestFoo(unittest.TestCase):
  @mock.patch('mymodule.code.foo.sum')
  def test_foo(foo_sum_mock):
    foo()
    foo_sum_mock.assert_called_once()

However, the patching approach illustrated above does not work. I believe that the sum function is patched correctly when loading mymodule.code.py, but redefined due to the def sum() block.

By reading the official documentation, I also tried to use the start and stop functions of the unittest.mock library as follows:

def test_foo():
  patcher = mock.patch('module.code.sum')
  mocked_sum_fun = patcher.start()

  foo()

  mocked_sum_fun.assert_called_once()
  mock_sum_fun.stop()

This approach also did not work. I was hoping it would avoid the sum function override after the modules/code.py file gets loaded.

Is it possible to patch a local function such as sum? Or is moving the sum function to another file the only option for patching?

Many thanks in advance!

like image 926
NickJaremek Avatar asked Nov 10 '17 12:11

NickJaremek


1 Answers

You can mock a function of same module using mock.patch and refering this module as __main__

code.py

from unittest.mock import patch

def sum():
    print("called method sum")
    pass

def call_sum():
    sum()

def return_mock():
    print("I'm a mocked method")
    return True

with patch('__main__.sum', return_value=return_mock()) as mock_test:
    call_sum()
    mock_test.assert_called_once() # assure that mocked method was called, not original.

You could also use the path of lib (my_project.code.sum) instead of __main__.sum.

like image 78
Mauro Baraldi Avatar answered Sep 20 '22 16:09

Mauro Baraldi