Mock function from other module - python

I have two python files:
function.py:
def foo ():
return 20
def func ():
temp = foo()
return temp
and mocking.py:
from testing.function import *
import unittest
import mock
class Testing(unittest.TestCase):
def test_myTest(self):
with mock.patch('function.func') as FuncMock:
FuncMock.return_value = 'string'
self.assertEqual('string', func())
I want to mock func, but with no positive result. I have AssertionError: 'string' != 20. What should I do to mock it correctly ? If I do mock.patch ('func') I have TypeError: Need a valid target to patch. You supplied: 'func'. If I move func to mocking.py and call foo: function.foo() it works correctly. But how to do it when I don't want to move functions from function.py to mocking.py ?

Mocking is useful when you're calling an actual function but you want some function calls inside that function to be mocked out. In your case you're aiming to mock func and you wish to call that mocked function directly by doing func().
However that won't work because you're mocking function.func but you've imported func already into your test file. So the func() that you're calling is an actual function, it's not the same as the mocked FuncMock. Try calling FuncMock() and you'll get the result as expected.
The following should work and it gives you an idea of what can be done:
from testing.function import func
import unittest
import mock
class Testing(unittest.TestCase):
def test_myTest(self):
with mock.patch('testing.function.foo') as FooMock:
FooMock.return_value = 'string'
self.assertEqual('string', func())

Related

Python: Getting mocked function value returned, not MagicMock, without adding returnvalue

So, basically I want to mock a function imported in another class, and for some reason I can't retrieve the mocked result without calling returnvalue of the mock.
This is the setup: one file, one module, one test class. I want to mock functionB() in source.fileB.
source.fileB
def functionB():
print('toto')
source.fileA
from source.fileB import *
def functionA():
print("bar")
return functionB()
Test case
from source.fileA import functionA
from source.fileA import functionB
#mock.patch('source.fileA.functionB')
def test_functionA(functionB_mock):
functionB_mock().returnvalue = "foo"
print(functionB_mock) # prints MagicMock object named functionB
print(functionB_mock.returnvalue) # prints MagicMock object name functionB.returnvalue
print(functionB_mock().returnvalue) #prints "foo"
print(functionA().returnvalue) #executes functionA, prints both "bar" and "foo"
print(functionA()) #executes functionA, prints both "bar" and MagicMock object named functionB()
So every time I try to get the result of the mocked functionB(), I have to use returnvalue. This is driving me nuts as I cannot update functionA() with
return functionB().returnvalue
in order for the rest of the code under test to execute properly.
I must be doing something wrong, but I can't understand what precisely.
There are two problems:
The mock attribute you want is return_value, not returnvalue!
You need to set that attribute on the mock itself, not the result of calling the mock (which is a different mock).
Here's a self-contained (single-file) version of your test code with the fix and some explanatory comments.
import mock
def functionB():
print('toto')
def functionA():
print("bar")
return functionB()
#mock.patch('__main__.functionB')
def test_functionA(functionB_mock):
functionB_mock.return_value = "foo"
# Prints a mock object because that's what functionB_mock is.
print(functionB_mock)
# Prints "foo" because that's what functionB_mock returns.
print(functionB_mock())
# The following two lines would raise AttributeError because
# "foo" isn't a Mock and doesn't have a 'return_value' attribute!
# print(functionB_mock().return_value)
# print(functionA().return_value)
# Executes functionA, prints "bar" and "foo"
print(functionA())
test_functionA()

How to mock a method call in a global variable

I was checking this trying to assign a method call in a module-level variable with the intention of being executed only once, but not sure why before running any of my unit tests it will pass through all the global references of the module, the problem with this is that I have a third party method that I am assigning to a global variable and fails because is trying to execute the actual method in this first pass through, I see that this behaviour is the same even with a simple local method, here an example to replicate it, this is in a file called
project_name.app.py
def printing_values():
# this is corrected mocked, as I am using patch in unit test to
# mock this but only available in the context of the test but not
# globally
print('from mocked printing_values method', SSM_VALUE)
return SSM_VALUE
def get_ssm():
return "value_from_method"
# this line will execute get_ssm before any unit test,
# how mock this to always have a mock value
SSM_VALUE = get_ssm()
Here is my unit test
""" response_transformer TESTS """
import unittest
from unittest import mock
import project_name.app
class TestGlobalVariable(unittest.TestCase):
#mock.patch('project_name.app.SSM_VALUE', 'testing_value')
def test_success_response_global_variable(self):
response = project_name.app.printing_values()
assert response == "testing_value"
So I would like to mock SSM_VALUE but not executing the get_ssm method associated with it, how should I achieve this?
""" response_transformer TESTS """
import unittest from unittest import mock
import project_name.app
class TestGlobalVariable(unittest.TestCase):
#mock.patch('project_name.app.printing_values')
def test_success_response_global_variable(self, mock_printing_values):
mock_printing_values.return_value = 'testing_value'
response = project_name.app.printing_values()
assert response == "testing_value"

Mock method of an object inside function [python]

I have two files:- file1.py and file2.py
file2.py has following code:-
import json
def fun1():
s = "{'function1': 'val1'}"
s = json.dumps(s)
print("in fun1 ", s)
return s
def fun2():
s = "{'function2': 'value2'}"
s = json.dumps(s)
print("in fun2 ", s)
return s
def fun5():
fun2()
return fun1()
file1.py has following code
from mockito import when, unstub
from file2 import fun5
def mock_the_function():
when("file2.fun1.json").dumps(...).thenReturn("something something")
print(fun5())
unstub()
I want to mock "dumps" inside "fun1" only, not "fun2". Code which I have written is showing error. I don't want to do it by parameter comparison. Is there any other way I can have a function being passed inside "when"?
First a quick note:
json.dumps takes an object, not a string, so it's kind of redundant to to call it as you are inside fun1 and fun2. Perhaps you're looking for json.loads?
Next I'd consider some different approaches:
When you mock json.dumps, you want to mock the the json property of the file2 module, so it would just be when("file2.json")... in the setup code for your test.
Because (as above), we're mocking the json module globally in the file2 module, it's not possible to, as you asked, in that context of a single test, mock json.dumps inside of fun1 but not fun2, but what I'd suggest is to simply have two tests, and unstub in a tear down method. For example:
from unittest import TestCase
class TestExample(TestCase):
def tearDown(self):
unstub()
def test_fun1(self):
when("file2.json").dumps(...).thenReturn("something something")
# in this invocation json is stubbed
self.assertEqual(fun1(), "something something")
def test_fun2(self):
# but now unstub has been called so it won't be stubbed anymore.
self.assertEqual(fun2(), "...output of fun2...")
Another alternative is for fun1 and fun2 to take a function that will do the work that the global json module is currently doing. This use of the Dependency Inversion Principle makes the code more testable, and means you don't even need mockito in your tests. For example:
def fun1(json_decoder):
s = "..."
return json_decoder(s)
# ....
from unittest.mock import MagicMock
def test_fun_1():
mock_decoder = MagicMock()
mock_decoder.return_value = "asdf"
assert fun1(mock_decoder) == "asdf"

Python unittest: Unable to mock imported functions so that conditional evaluates to False

I'm encountering a problem with unit testing in Python. Specifically, when I try to mock a function my code imports, variables assigned to the output of that function get assigned to a MagicMock object instead of the mock-function's return_value. I've been digging through the docs for python's unittest library, but am not having any luck.
The following is the code I want to test:
from production_class import function_A, function_B, function_M
class MyClass:
def do_something(self):
variable = functionB()
if variable:
do_other_stuff()
else:
do_something_else
this is what I've tried:
#mock.patch(path.to.MyClass.functionB)
#mock.patch(<other dependencies in MyClass>)
def test_do_something(self, functionB_mock):
functionB_mock.return_value = None # or False, or 'foo' or whatever.
myClass = MyClass()
myClass.do_something()
self.assertTrue(else_block_was_executed)
The issue I have is that when the test gets to variable = functionB in MyClass, the variable doesn't get set to my return value; it gets set to a MagicMock object (and so the if-statement always evaluates to True). How do I mock an imported function such that when executed, variables actually get set to the return value and not the MagicMock object itself?
We'd have to see what import path you're actually using with path.to.MyClass.functionB. When mocking objects, you don't necessarily use the path directly to where the object is located, but the one that the intepreter sees when recursively importing modules.
For example, if your test imports MyClass from myclass.py, and that file imports functionB from production_class.py, the mock path would be myclass.functionB, instead of production_class.functionB.
Then there's the issue that you need additional mocks of MyClass.do_other_stuff and MyClass.do_something_else in to check whether MyClass called the correct downstream method, based on the return value of functionB.
Here's a working example that tests both possible return values of functionB, and whether they call the correct downstream method:
myclass.py
from production_class import functionA, functionB, functionM
class MyClass:
def do_something(self):
variable = functionB()
if variable:
self.do_other_stuff()
else:
self.do_something_else()
def do_other_stuff(self):
pass
def do_something_else(self):
pass
production_class.py
import random
def functionA():
pass
def functionB():
return random.choice([True, False])
def functionM():
pass
test_myclass.py
import unittest
from unittest.mock import patch
from myclass import MyClass
class MyTest(unittest.TestCase):
#patch('myclass.functionB')
#patch('myclass.MyClass.do_something_else')
def test_do_something_calls_do_something_else(self, do_something_else_mock, functionB_mock):
functionB_mock.return_value = False
instance = MyClass()
instance.do_something()
do_something_else_mock.assert_called()
#patch('myclass.functionB')
#patch('myclass.MyClass.do_other_stuff')
def test_do_something_calls_do_other_stuff(self, do_other_stuff_mock, functionB_mock):
functionB_mock.return_value = True
instance = MyClass()
instance.do_something()
do_other_stuff_mock.assert_called()
if __name__ == '__main__':
unittest.main()
calling python test_myclass.py results in:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
What I wound up doing was changing the import statements in MyClass to import the object instead of the individual methods. I was then able to mock the object without any trouble.
More explicitly I changed MyClass to look like this:
import production_class as production_class
class MyClass:
def do_something(self):
variable = production_class.functionB()
if variable:
do_other_stuff()
else:
do_something_else
and changed my test to
#mock.patch(path.to.MyClass.production_class)
def test_do_something(self, prod_class_mock):
prod_class_mock.functionB.return_value = None
myClass = MyClass()
myClass.do_something()
self.assertTrue(else_block_was_executed)

Test instance of class that mocked method is called from in Python

I am mocking out a method of a class and want to test the instance of the class that the method was called from to test that the creation part of my function works as expected.
In my particular case do_stuff tries to write bar_instance to an Excel File and I don't want that to happen i.e.
def create_instance(*args):
return Bar(*args)
class Bar():
def __init__(self, *args):
self.args = args
def do_stuff(self):
pass
def foo(*args):
bar_instance = create_instance(*args)
bar_instance.do_stuff()
Then in a testing file
from unittest import TestCase
from unittest.mock import patch
from path.to.file import foo
class TestFoo(TestCase):
#patch('path.to.file.Bar.do_stuff')
def test_foo(self, mock_do_stuff):
test_args = [1]
_ = foo(*test_args)
# Test here the instance of `Bar` that `mock_do_stuff` was called from
# Something like
actual_args = list(bar_instance.args)
self.assertEqual(test_args, actual_args)
I put a break in the test function after foo(*test_args) is run but can't see any way from the mocked method of accessing the instance of Bar it was called from and am a bit stuck. I don't want to mock out Bar further up the code as I want to make sure the correct instance of Bar is being created.
In your code example, there are three things that might need testing: function create_instance, class Bar and function foo. I understand your test code such that you want to ensure that function foo calls do_stuff on the instance returned by create_instance.
Since the original create_instance function has control over the created instance, a solution of your problem is to mock create_instance such that your test gains control of the object that is handed over to foo:
import unittest
from unittest import TestCase
from unittest.mock import patch, MagicMock
from SO_60624698 import foo
class TestFoo(TestCase):
#patch('SO_60624698.create_instance')
def test_foo_calls_do_stuff_on_proper_instance (
self, create_instance_mock ):
# Setup
Bar_mock = MagicMock()
create_instance_mock.return_value = Bar_mock
# Exercise
foo(1, 2, 3) # args are irrelevant
# Verify
Bar_mock.do_stuff.assert_called()
if __name__ == '__main__':
unittest.main()
In addition, you might also want to test if foo passes the arguments correctly to create_instance. This could be implemented as a separate test:
...
#patch('SO_60624698.create_instance')
def test_foo_passes_arguments_to_create_instance (
self, create_instance_mock ):
# Setup
create_instance_mock.return_value = MagicMock()
# Exercise
foo(1, 22, 333)
# Verify
create_instance_mock.assert_called_with(1, 22, 333)
And, certainly, to complete the whole test of the object generation, you could test create_instance directly, by calling it and checking on the returned instance of Bar if it has used its arguments correctly for the construction of the Bar instance.
As patch returns an instance of Mock (or actually MagicMock, but it inherits the relevant methods from its base - Mock), you have the assert_called_with method available, which should do the trick.
Note that this method is sensitive to args/kwargs - you have to assert the exact same call.
Another note: it might be a better practice to use patch.object instead of patch here

Categories

Resources