0

My python file has many methods defined in it. In many of the methods in the file, I am calling a function - let's say "fun1".

I want to mock the 'fun1' function for each of the methods differently. Is there a way to patch an object differently at method level and not at file level?

 Contents of aPythonFile.py
=======================================
    import fun from a_module

    def a():
        res= fun(aarg1, aarg2)
        return res

    def b():
        res = fun(barg1, barg2)
        return res

This came to my mind, as I know, the same "fun" can be patched differently for different files, then why not be able to patch differently based on the method in the file where it is called :-

@mock.patch("package.aPythonFile.fun") - Is Valid

@mock.patch("package.aPythonFile.a.fun") - ?? (possible?)
@mock.patch("package.aPythonFile.b.fun") - ?? (possible?)
Lin Du
  • 88,126
  • 95
  • 281
  • 483
VISHAL DAGA
  • 4,132
  • 10
  • 47
  • 53
  • This answer ( https://stackoverflow.com/questions/15753390/how-can-i-mock-requests-and-the-response) is not answering my question. What is suggested there is already known and followed by me. For my case, I want to organize the code more cleanly which this current approach (or the one referred as duplicate) is not providing! – VISHAL DAGA Mar 19 '21 at 12:01
  • I am not sure what you are getting at. `@mock.patch` applies to an individual test method, so if you have a `test_a` and `test_b`, they can be patched with different methods. You do realize [one of the answers](https://stackoverflow.com/a/65437794) in that thread literally has the mocking done at the method level, you can just change the argument passed to `side_effect` to the method you specifically require for the specific test... – metatoaster Mar 19 '21 at 12:46
  • It would then be useful to include how you are currently testing that `aPythonFile.py` of yours. Your edited code has only make your question even more confusing. You need to show _clearly_ what you are doing. If you want different return values for `fun1` that were called throughout an execution you may wish to refer to [this thread](https://stackoverflow.com/a/56191297/). In any case please clean up your question because as it is now is quite unclear on what you are asking, but at least you made it not obviously a duplicate of the other question, though as is it is still unanswerable. – metatoaster Mar 19 '21 at 14:39
  • Ok thanks, I have edited it (hopefully its more clear). I am new with testing in python, but when I am learning about mock(ing) with inbuilt unit test, I feel that it is quite common that the object which is being mocked could be called several times in a file in practical scenario. I see that the module 'unittest.mock' allows an object to patch differently per file level in a package, then why not there is a way to patch an object, for example - able to patch it differently based on the method in which it is being in the file – VISHAL DAGA Mar 19 '21 at 16:56
  • I am trying to architect a more manageable testing infrastructure for my team, and I wanted to have clear understanding if what i am asking is possible or not. I have searched through web and SO, but didn't find any information that clearly says if this is not possible – VISHAL DAGA Mar 19 '21 at 17:01
  • 1
    It's possible. Mock the function with [side_effect](https://stackoverflow.com/a/7665754/362792) replacement function. Inside your side_effect function, get the function [name of caller](https://stackoverflow.com/a/900404/362792), then do different code based on which caller is it. Alternatively, instead of caller name you can vary behaviour based on argument values instead. – Hitobat Mar 19 '21 at 18:29
  • It's more of a general programming question then, I too had thought about it. Somehow, I got lost in thinking that there could be a more standard way - 'mock' module way, but you comment gives me confidence there' no need... I think you could have had made your comment as an answer instead. As comment may not be obvious if someone else like me happens to have the same question... – VISHAL DAGA Mar 19 '21 at 18:42

1 Answers1

0

Just provide different mock_fun.return_value for each test case.

E.g.

a_module.py:

def fun(a, b):
    pass

a_python_file.py:

from a_module import fun


def a():
    res = fun('a1', 'a2')
    return res


def b():
    res = fun('b1', 'b2')
    return res

test_a_python_file.py:

import unittest
from unittest import mock
from a_python_file import a, b


class TestAPythonFile(unittest.TestCase):
    @mock.patch('a_python_file.fun')
    def test_a(self, mock_fun):
        mock_fun.return_value = 'return value for a'
        actual = a()
        self.assertEqual(actual, 'return value for a')

    @mock.patch('a_python_file.fun')
    def test_b(self, mock_fun):
        mock_fun.return_value = 'return value for b'
        actual = b()
        self.assertEqual(actual, 'return value for b')


if __name__ == '__main__':
    unittest.main()

unit test result:

⚡  coverage run /Users/dulin/workspace/github.com/mrdulin/python-codelab/src/stackoverflow/66707457/test_a_python_file.py && coverage report -m --include='./src/**'  
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
Name                                               Stmts   Miss  Cover   Missing
--------------------------------------------------------------------------------
src/stackoverflow/66707457/a_module.py                 2      1    50%   2
src/stackoverflow/66707457/a_python_file.py            7      0   100%
src/stackoverflow/66707457/test_a_python_file.py      16      0   100%
--------------------------------------------------------------------------------
TOTAL                                                 25      1    96%
Lin Du
  • 88,126
  • 95
  • 281
  • 483