So I'm running py.test and trying to use monkeypatch. I understand that monkeypatch's intended purpose is to replace attributes in a module so that they can be tested. And I get that we can substitute in mock functions in order to do this.
Currently I am trying to run essentially the following block of code.
from src.module.submodule import *
def mock_function(parameter = None):
return 0
def test_function_works(monkeypatch):
monkeypatch.setattr("src.module.submodule.function",mock_function ]
assert function(parameter = None) == 0
When the test runs, instead of swapping in mock_function, it just runs function . Could there be a reason why monkeypatch isn't activating
I have got monkey patch running succesfully with other code before. So I don't see why this isn't working.
I haven't used pytest for this stuff, but I know that with the mock library, functions are patched in the namespace where they're called. i.e. from src.module.submodule import * imports src.module.submodule.function into your namespace, but you then patch it in its original namespace, so your local name for the function still accesses the original, unpatched code.
If you change this to
import src.module.submodule
def mock_function(parameter = None):
return 0
def test_function_works(monkeypatch):
monkeypatch.setattr("src.module.submodule.function",mock_function ]
assert src.module.submodule.function(parameter = None) == 0
does it succeed?
Looks like a typo, shouldn't it be
monkeypatch.setattr("src.module.submodule.function",mockIfunction)
i.e. mockIfunction instead of mock_function?
Related
The initial scenerio is writing tests for functions from a library (lib.py).
lib.py:
def fun_x(val):
# does something with val
return result
def fun(val):
x = fun_x(val)
# does seomthing with x
return result
test__lib.py
import pytest
import lib
def lib_fun_x_mocked(val):
return "qrs"
def test_fun():
assert lib.fun("abc") == "xyz"
But lib.fun_x() does something very expensive or requires a resource not reliably available or not determinisitc. So I want to subsitute it with a mock function such that when the test test_fun() is executed lib.fun() uses lib_fun_x_mocked() instead of fun_x() from its local scope.
So far I'm running into cryptic error messages when I try to apply mock/patch recipes.
You can use the built-in fixture monkeypatch provided by pytest.
import lib
def lib_fun_x_mocked(some_val): # still takes an argument
return "qrs"
def test_fun(monkeypatch):
with monkeypatch.context() as mc:
mc.setattr(lib, 'fun_x', lib_fun_x_mocked)
result = lib.fun('abc')
assert result == 'qrs'
Also as a side note, if you are testing the function fun you shouldn't be asserting the output of fun_x within that test. You should be asserting that fun behaves in the way that you expect given a certain value is returned by fun_x.
I'm trying to mock a function used within the function I'm testing, but for some reason I'm not seeing the original function always runs, not the one I created as a mock.
The code I'm testing has this type of setup:
def function_being_tested(foo):
...
function_i_want_to_mock(bar)
...
def function_i_want_to_mock(bar)
print("Inside original function")
...
I've installed Mock and I've tried using unittest.mock patch
Currently the test file uses this setup:
import mock
from django.test import TestCase
def mock_function_i_want_to_mock(bar):
print(bar)
return True
class SupportFunctionsTestCases(TestCase):
#mock.patch("path.to.function.function_i_want_to_mock", mock_function_i_want_to_mock)
def test_function_being_tested(self):
# setup
result = function_being_tested(test_foo)
self.assertEqual(result, expected_result)
What then happens is when I run the test, I always get: "Inside original function", not the parameter printed so it's always running the original function.
I've used this exact setup before and it has worked so I'm not sure what's causing this. Probably some wrong setup...
If anyone has a different way of doing this or spots some error, it would be appreciated.
"path.to.function.function_i_want_to_mock" should be a path to where the function is used, not defined.
So if function_i_want_to_mock is defined in moduleA.py but imported and used in moduleB.py which you are testing then you should use #mock.patch("path.to.moduleB.function_i_want_to_mock", ...).
So let's say I have this bit of code:
import coolObject
def doSomething():
x = coolObject()
x.coolOperation()
Now it's a simple enough method, and as you can see we are using an external library(coolObject).
In unit tests, I have to create a mock of this object that roughly replicates it. Let's call this mock object coolMock.
My question is how would I tell the code when to use coolMock or coolObject? I've looked it up online, and a few people have suggested dependency injection, but I'm not sure I understand it correctly.
Thanks in advance!
def doSomething(cool_object=None):
cool_object = cool_object or coolObject()
...
In you test:
def test_do_something(self):
cool_mock = mock.create_autospec(coolObject, ...)
cool_mock.coolOperation.side_effect = ...
doSomthing(cool_object=cool_mock)
...
self.assertEqual(cool_mock.coolOperation.call_count, ...)
As Dan's answer says, one option is to use dependency injection: have the function accept an optional argument, if it's not passed in use the default class, so that a test can pass in a moc.
Another option is to use the mock library (here or here) to replace your coolObject.
Let's say you have a foo.py that looks like
from somewhere.else import coolObject
def doSomething():
x = coolObject()
x.coolOperation()
In your test_foo.py you can do:
import mock
def test_thing():
path = 'foo.coolObject' # The fully-qualified path to the module, class, function, whatever you want to mock.
with mock.patch('foo.coolObject') as m:
doSomething()
# Whatever you want to assert here.
assert m.called
The path you use can include properties on objects, e.g. module1.module2.MyClass.my_class_method. A big gotcha is that you need to mock the object in the module being tested, not where it is defined. In the example above, that means using a path of foo.coolObject and not somwhere.else.coolObject.
I want to test a function in python, but it relies on a module-level "private" function, that I don't want called, but I'm having trouble overriding/mocking it. Scenario:
module.py
_cmd(command, args):
# do something nasty
function_to_be_tested():
# do cool things
_cmd('rm', '-rf /')
return 1
test_module.py
import module
test_function():
assert module.function_to_be_tested() == 1
Ideally, in this test I dont want to call _cmd. I've looked at some other threads, and I've tried the following with no luck:
test_function():
def _cmd(command, args):
# do nothing
pass
module._cmd = _cmd
although checking module._cmd against _cmd doesn't give the correct reference. Using mock:
from mock import patch
def _cmd_mock(command, args):
# do nothing
pass
#patch('module._cmd', _cmd_mock)
test_function():
...
gives the correct reference when checking module._cmd, although `function_to_be_tested' still uses the original _cmd (as evidenced by it doing nasty things).
This is tricky because _cmd is a module-level function, and I dont want to move it into a module
[Disclaimer]
The synthetic example posted in this question works and the described issue become from specific implementation in production code. Maybe this question should be closed as off topic because the issue is not reproducible.
[Note] For impatient people Solution is at the end of the answer.
Anyway that question given to me a good point to thought: how we can patch a method reference when we cannot access to the variable where the reference is?
Lot of times I found some issue like this. There are lot of ways to meet that case and the commons are
Decorators: the instance we would like replace is passed as decorator argument or used in decorator static implementation
What we would like to patch is a default argument of a method
In both cases maybe refactor the code is the best way to play with that but what about if we are playing with some legacy code or the decorator is a third part decorator?
Ok, we have the back on the wall but we are using python and in python nothing is impossible. What we need is just the reference of the function/method to patch and instead of patching its reference we can patch the __code__: yes I'm speaking about patching the bytecode instead the function.
Get a real example. I'm using default parameter case that is simple, but it works either in decorator case.
def cmd(a):
print("ORIG {}".format(a))
def cmd_fake(a):
print("NEW {}".format(a))
def do_work(a, c=cmd):
c(a)
do_work("a")
cmd=cmd_fake
do_work("b")
Output:
ORIG a
ORIG b
Ok In this case we can test do_work by passing cmd_fake but there some cases where is impossible do it: for instance what about if we need to call something like that:
def what_the_hell():
list(map(lambda a:do_work(a), ["c","d"]))
what we can do is patch cmd.__code__ instead of _cmd by
cmd.__code__ = cmd_fake.__code__
So follow code
do_work("a")
what_the_hell()
cmd.__code__ = cmd_fake.__code__
do_work("b")
what_the_hell()
Give follow output:
ORIG a
ORIG c
ORIG d
NEW b
NEW c
NEW d
Moreover if we want to use a mock we can do it by add follow lines:
from unittest.mock import Mock, call
cmd_mock = Mock()
def cmd_mocker(a):
cmd_mock(a)
cmd.__code__=cmd_mocker.__code__
what_the_hell()
cmd_mock.assert_has_calls([call("c"),call("d")])
print("WORKS")
That print out
WORKS
Maybe I'm done... but OP still wait for a solution of his issue
from mock import patch, Mock
cmd_mock = Mock()
#A closure for grabbing the right function code
def cmd_mocker(a):
cmd_mock(a)
#patch.object(module._cmd,'__code__', new=cmd_mocker.__code__)
test_function():
...
Now I should say never use this trick unless you are with the back on the wall. Test should be simple to understand and to debug ... try to debug something like this and you will become mad!
Say I want to test this module:
import osutils
def check_ip6(xml):
ib_output = osutils.call('iconfig ib0')
# process and validate ib_output (to be unit tested)
...
This method is dependent on the environment, because it makes a System call (which expects a specific network interface), so its not callable on a testmachine.
I want to write a Unit test for that method which checks if the processing of ib_output works as expected. Therefore I want to mock osutils.call and let it just return testdata. What is the preferred way to do that? Do I have to do mocking or (monkey) patching?
Example test:
def test_ib6_check():
from migration import check_ib6
# how to mock os_utils.call used by the check_ib6-method?
assert check_ib6(test_xml) == True
One solution would be to do from osutils import call and then when patching things replace yourmodule.call with something else before calling test_ib6_check.
Ok, I found out that this has nothing to do with mocks, afaik I just need a monkey patch: I need to import and change the osutils.call-method and then import the method under test (and NOT the whole module, since it would then import the original call-method) afterwards. So this method will then use my changed call-method:
def test_ib6_check():
def call_mock(cmd):
return "testdata"
osutils.call = call_mock
from migration import check_ib6
# the check_ib6 now uses the mocked method
assert check_ib6(test_xml) == True