Python monkey patch private function

徘徊边缘 提交于 2019-12-05 06:44:08

I can't seem to reproduce your issue (I've tweaked your example a bit, since it doesn't run at all as-is). Did you just mistype something (like mymodule._b instead of mymodule.__b)?

mymodule.py:

def a(x):
    return __b("someval")

def __b(args):
    return "complex_thingy: {}".format(args)

mytest.py:

from unittest import TestCase

import mymodule

def newfn(args):
    return {"a" : "b"}

mymodule.__b = newfn

class TestMyModule(TestCase):
    def test_basic(self):
        print(mymodule.a('somearg'))

Output:

C:\TEMP>python -m unittest mytest
{'a': 'b'}
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

C:\TEMP>

Seems to work fine.


Or outside of unittest:

mytest2.py:

import mymodule

def newfn(args):
    return {"a" : "b"}

mymodule.__b = newfn

print(mymodule.a('somearg'))

Output:

C:\TEMP>python mytest2.py
{'a': 'b'}

C:\TEMP>

If your module was named 'foo', then the following should work.

import foo

def patched_version():
    return 'Hello'

foo.__b = patched_version

print (foo.a())

where foo.py is

def a():
    return __b()

def __b():
    return 'Goodbye'

I was facing the same problem, but finally got to the solution. The problem was when using the monkey patch in the unittest.TestCase class. Here's the solution that works just fine:

If you are using Python 2, you'll need to install the "mock" library (http://www.voidspace.org.uk/python/mock/) using easy_install or some other way. This library is already bundled with Python 3.

Here's what the code looks like:

from mock import patch

    class TestMyModule(TestCase):
        def test_basic(self):
            with patch('mymodule._b') as mock:
                mock.return_value={"a" : "b"} # put here what you want the mock function to return. You can make multiple tests varying these values.
                #keep the indentation. Determines the scope for the patch.
                print(mymodule.a('somearg'))

Although this way apparently seems a bit less convenient compared to making a mock function where we could mimic the actual sub-function, _b(), having logic to return different values based on different arguments, but then we unnecessarily add more chances of error. In this approach we just hard-code what we want our mocked function to return and test the actual function we set out to test, that was a().

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!