Mocking function that is implicitly imported into a module - python

I would like to mock a function inside a module, however, this function is not explicitly imported. Consider following scenario.
helper_functions.py
def foo_1():
...
def foo_2():
...
helper_functions = [foo1, foo2]
my_module
from helper_functions import helper_functions
def do_something(foo):
...
some_results = [do_something(foo) for foo in helper_functions]
I need to patch ONLY foo2 but in my_module, because I'm basically testing how do_something works.
When I try this
from unittest import patch
#patch('my_module.foo2')
def test_do_something():
...
I get an obvious error saying that foo2 does not exist in the namespace of my_module.
Can I bypass it somehow?

Related

Python pass variable to imported module at "compilation" time

I'm trying to create an object from a custom class with a decorator in it.
Then I need to use the decorator of that object to create a bunch of functions in a different file.
I found the solution of using builtins online but it feels a bit hacky and makes my lsp spit out a bunch of errors.
I'm wondering if anyone knows a better solution.
This is my file structure:
main.py
mylib
├── A.py
└── B.py
main.py
import builtins
from mylib.A import A
a = A("This is printing in the decorator")
builtins.FOO = a
import mylib.B as B
B.foo()
B.poo()
A.py
class A:
def __init__(self, _message):
self.message = _message
def our_decorator(self, func):
def function_wrapper():
print(self.message)
func()
return function_wrapper
B.py
import builtins
#builtins.FOO.our_decorator
def foo():
print("foo")
#builtins.FOO.our_decorator
def poo():
print("poo")
I don't want to change the file structure if it can be avoided.
Using builtins to have a magically created decorator is indeed hacky.
An alternative would be to patch the functions in B from main. It is slightly cleaner (and linters should not complain) because the B module has no longer to be aware of the decorator:
main.py:
from mylib.A import A
a = A()
import mylib.B as B
# decorate here the functions of the B module
B.foo = a.our_decorator(B.foo)
B.poo = a.our_decorator(B.poo)
B.foo()
B.poo()
A.py is unchanged...
B.py:
def foo():
print("foo")
def poo():
print("poo")
As only one version of a module exists in a process, you can even use the functions of B from a third module, provided:
either it is imported after the decoration
or it only imports the module name (import mylib.B as B) and not directly the functions (from mylib.B import foo)

monkeypatching not carrying through class import

I'm trying to test some code using pytest and need to change a function from some module. One of my imports also imports that function, but this is failing when I change the method using monkeypatch. Here is what I have:
util.py
def foo():
raise ConnectionError # simulate an error
return 'bar'
something.py
from proj import util
need_this = util.foo()
print(need_this)
test_this.py
import pytest
#pytest.fixture(autouse=True)
def fix_foo(monkeypatch):
monkeypatch.setattr('proj.something.util.foo', lambda: 'bar')
import proj.something
And this raises ConnectionError. If I change
test_this.py
import pytest
#pytest.fixture(autouse=True)
def fix_foo(monkeypatch):
monkeypatch.setattr('proj.something.util.foo', lambda: 'bar')
def test_test():
import proj.something
Then it imports with the monkeypatch working as expected. I've read though this and tried to model my testing from it, but that isn't working unless I import inside of a test. Why does the monkeypatch not do anything if it is just a normal import in the testing file?
That is because the fixture is applied to the test function not the entire code. autouse=True attribute just says that it should be used in every test

Python unittest - testing multiple files with the same name

I am attempting to test multiple functions with the same name and signature. (Student assignment submissions.) My setup currently looks like this:
TestCases/
__init__
testcase1.py
submission1/
func.py
submission2/
func.py
submission3/
func.py
Each func.py contains a function named foo. I would like to test each occurrence of foo with the same test suite. The standard unittest setup of
import unittest
from func import foo
class TestFoo(unittest.TestCase):
def test_empty(self):
self.assertTrue(foo(''))
...
if __name__ == '__main__':
unittest.main()
has (unsurprisingly) problems with the from func import foo line since func is not in the same folder, and I cannot seem to get it to pick up the proper import dynamically.
It struck me that I could take advantage of having already extended the base class and eliminate the need for the import by doing something like:
import unittest
class TestFoo(unittest.TestCase):
def __init__(self, foo):
self.foo = foo
def test_empty(self):
self.assertTrue(self.foo(''))
and in my test program instantiate a TestFoo object and pass it the function to test:
tf = TestFoo(foo)
but then I haven't been able to properly define and call the test suite.
Or is there an entirely different approach that would do what I need?

Using patch to to mock a function (as opposed to a method)

I want to do something like the following example (found here)
>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
... thing = ProductionClass()
... thing.method(1, 2, 3)
However this is patching the method called method on ProductionClass. I want to patch a generic function within a context. Ideally something looking like...
with path.something(my_fn, return_value=my_return) as mock_function:
do_some_other_fn()
my_fn is called deep within do_some_other_fn and therefore is difficult to mock out directly. This seems like it should be straight forward but I can't find the right syntax
EDIT In the module that do_some_other_fn lives I import my_fn like followings
from my_module import my_fn
So I need a way to be able to tell mock to patch that from outside the module. Is this possible?
EDIT 2 I think this makes it more clear what I am looking for
This works but is not ideal:
import my_module
with patch('my_module.fn', return_value='hello') as patch_context:
x = my_module.fn()
# x now contains 'hello'
However I would much rather have it work like this (or something similar)
from my_module import fn
with patch('my_module.fn', return_value='hello') as patch_context:
x = fn()
# x contains real result from real call to fn()
Your attempt to patch with from my_module import fn does not work because the import statement creates a local symbol fn which points to whatever value fn has in my_module at the time of import. You later patch my_module.fn but it does not matter because you already have a local copy of fn.
If the file that contains the patch call is the main module (the file that python initially loaded), you should be able to do it by patching __main__.fn:
from my_module import fn
with patch('__main__.fn', return_value='hello') as patch_context:
x = fn()
If the file that contains the patch call is loaded as a module from the main module then __main__ won't work and you need to pass the absolute module name of the module that contains your patch call to patch rather than __main__.
You can see function like module object's static method. To patch a function func in module mymodule you can use
patch("mymodule.func", return_value=my_return)
You should take care of Where to patch and if the function is in the same module where you have the test should use "__main__.func" as patch argument.
patch like patch.object can be useed as decorator, context or by start() and stop() method.
Now when in a module you import a function from an other module like:
from mymodule import func as foo
You create a new reference to func in the new module called foo. Every
time in this module you call foo you will use the reference to mymodule.func that you load when you imported it: if you whould like change this behavior you should patch foo in the new module.
To make it more clear I build an example where you have mymodule that contain func, module_a that include mymodule and use mymodule.func, module_b that use from mymodule import func as foo and use bot foo and mymodule.func
mymodule.py
def func():
return "orig"
module_a.py
import mymodule
def a():
return mymodule.func()
module_b.py
from mymodule import func as foo
import mymodule
def b_foo():
return foo()
def b():
return mymodule.func()
test.py
import unittest
from unittest.mock import *
import mymodule
import module_a
import module_b
class Test(unittest.TestCase):
def test_direct(self):
self.assertEqual(mymodule.func(), "orig")
with patch("mymodule.func", return_value="patched"):
self.assertEqual(mymodule.func(), "patched")
def test_module_a(self):
self.assertEqual(module_a.a(), "orig")
with patch("mymodule.func", return_value="patched"):
self.assertEqual(module_a.a(), "patched")
def test_module_b(self):
self.assertEqual(module_b.b(), "orig")
with patch("mymodule.func", return_value="patched"):
self.assertEqual(module_b.b(), "patched")
self.assertEqual(module_b.b_foo(), "orig")
with patch("module_b.foo", return_value="patched"):
self.assertEqual(module_b.b(), "orig")
self.assertEqual(module_b.b_foo(), "patched")
if __name__ == '__main__':
unittest.main()
In other words what really rules on choosing where to patch is how the function is referenced where you want use the patched version.

Python: Mocking a module that's being used by a module I'm testing

I would like to mock a certain module in order to test a piece of code that is using the module.
That is to say, I have a module my_module which I'd like to test. my_module imports an external module real_thing and calls real_thing.compute_something():
#my_module
import real_thing
def my_function():
return real_thing.compute_something()
I need to mock real_thing so that in a test it will behave like fake_thing, a module that I've created:
#fake_thing
def compute_something():
return fake_value
The test calls my_module.my_function() which calls real_thing.compute_something():
#test_my_module
import my_module
def test_my_function():
assert_something(my_module.my_function())
What should I add to the test code so that my_function() will call fake_thing.compute_something() within the test instead of real_thing.compute_something()?
I was trying to figure out how to do so with Mock, but I haven't.
Simply that no ? Hack the sys.modules
#fake_thing.py
def compute_something():
return 'fake_value'
#real_thing.py
def compute_something():
return 'real_value'
#my_module.py
import real_thing
def my_function():
return real_thing.compute_something()
#test_my_module.py
import sys
def test_my_function():
import fake_thing
sys.modules['real_thing'] = fake_thing
import my_module
print my_module.my_function()
test_my_function()
Outputs : 'fake_value'
http://code.google.com/p/mockito-python/
>>> from mockito import *
>>> dog = mock()
>>> when(dog).bark().thenReturn("wuff")
>>> dog.bark()
'wuff'
http://technogeek.org/python-module.html - how to replace ,load module dynamically

Categories

Resources