17

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!

asked Nov 10, 2017 at 12:47
1
  • 2
    Did you ever figure this out? I'm having the same issue. Commented Jul 17, 2021 at 0:36

2 Answers 2

6

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.

answered Jul 15, 2020 at 19:22
Sign up to request clarification or add additional context in comments.

5 Comments

Getting ModuleNotFoundError, '__main__' is not a package.
@Velkan check here the code running
@Velkan in this example, all the code is in just one file.
It depends heavily on how it's called. I've found somewhere that the reliable way is to use something like __name__ + '.sum'.
@Velkan You are right and the answer is misleading, you might want to edit it.
-3

Generally speaking, you'd want to separate your test code from your production code:

code.py

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()

code_test.py

import unittest
import mock_test as mock
import code
class TestFoo(unittest.TestCase):
 @mock.patch('code.sum')
 def test_foo(self, sum_mock):
 def new_sum_mock(*args, **kwargs):
 # mock code here
 pass
 sum_mock.side_effect = new_sum_mock
 code.foo()
 sum_mock.assert_called_once()

But yes, you could place it all into one file:

code_test.py:

import unittest
import mock_test as mock
import code
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()
class TestFoo(unittest.TestCase):
 @mock.patch('code_test.sum')
 def test_foo(self, sum_mock):
 def new_sum_mock(*args, **kwargs):
 # mock code here
 pass
 sum_mock.side_effect = new_sum_mock
 code.foo()
 sum_mock.assert_called_once()
answered Jan 7, 2019 at 23:04

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.