In a function I'm using uuid1 that I want to patch.
def myFunction():
my_value = uuid4.int
smth else..
I want to be able to mock my_value so it always returns the same number in my unit test, because I need it for further use.
I tried doing:
#patch('folder.myFunction.uuid4')
def test_myFunction(self, mock_value):
mock_value.return_value = 22222
But it throws an error saying myFunction does not have uuid4 as an attribute.
How do I mock its value?
The error you get is correct. Your function does not have a uuid4 attribute.
I'm reading between the lines assuming uuid4 is a method of the uuid module that normally generates a random uuid.
When testing you said you want it to always return the same value. To do that you can substitute a unittest.mock.Mock for uuid.uuid4.
In [36]: uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e'))
In [37]: uuid_mock()
Out[37]: UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e')
Something like this for testing the following function (f)
import uuid, unittest
from unittest.mock import Mock, patch
def f():
z = uuid.uuid4()
return z.int
The target for the patch is the uuid method - uuid.uuid4. Specify a unittest.mock.Mock with a fixed return value for the new parameter of the patch. During the test, the Mock will be substituted for uuid.uuid4
class TestF(unittest.TestCase):
uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e'))
good_uuid = uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e').int
bad_uuid = uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b5a31').int
#patch(target='uuid.uuid4', new=TestF.uuid_mock)
def test_myFunction_True(self):
self.assertEqual(f(), self.good_uuid)
#patch(target='uuid.uuid4', new=TestF.uuid_mock)
def test_myFunction_False(self):
self.assertNotEqual(f(), self.bad_uuid)
if __name__ == '__main__':
unittest.main()
Result:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
If you want to test a function that relies on f's return value and you want f to always return the same value during testing then make f the target for the patch.
def g():
return f() == uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e').int
class TestG(unittest.TestCase):
good_uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e').int)
bad_uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b5a31').int)
#patch(target='__main__.f', new=TestG.good_uuid_mock)
def test_myFunction_True(self):
self.assertTrue(g())
#patch(target='__main__.f', new=TestG.bad_uuid_mock)
def test_myFunction_False(self):
self.assertFalse(g())
It depends on your import. Let's say you have a module called module.py, and you have an import like this:
from uuid import uuid4
This means that in this module we now have a variable called uuid4. This is the thing to mock.
#patch('path.to.module.uuid4.int')
Related
I am working with the following code and test, which live in separate files:
#exchange.py
def on_indicative_price_volume(self, msg):
symbol = self.get_symbol(msg.security_id)
breakpoint()
price = msg.pre_open_price * symbol.deal_price_multiplier
self.write_auc(msg.security_id)
#test.py
#mock.patch('exchange.IceExchange.get_symbol')
def test_indicative_price_and_vol(mock_symbol, exchange):
mock_symbol.deal_price_multiplier = 25
So in my unit test, I have mocked out the functionget_symbol. So that when I print symbol where I set the breakpoint above, I get:
<MagicMock name='get_symbol().deal_price_multiplier.__rmul__()' id='14032624'>
So it has been mocked as expected. But now I want to set symbol.deal_price_multiplier in my function to return the value 25.
As you can see above in my unit test I tried to do mock_symbol.deal_price_multiplier = 25, but when I print symbol.deal_price_multiplier in my function I then get:
<MagicMock name='get_symbol().deal_price_multiplier.__rmul__()' id='14424'>
Which is not what I want, I want mock_symbol.deal_price_multiplier to simply return 25. How can I do this?
I had created a simple example to illustrate my issue. First is the setup say mydummy.py:
class TstObj:
def __init__(self, name):
self.name = name
def search(self):
return self.name
MyData = {}
MyData["object1"] = TstObj("object1")
MyData["object2"] = TstObj("object2")
MyData["object3"] = TstObj("object3")
def getObject1Data():
return MyData["object1"].search()
def getObject2Data():
return MyData["object2"].search()
def getObject3Data():
return MyData["object3"].search()
def getExample():
res = f"{getObject1Data()}{getObject2Data()}{getObject3Data()}"
return res
Here is the test that failed.
def test_get_dummy1():
dummy.MyData = MagicMock()
mydummy.MyData["object1"].search.side_effect = ["obj1"]
mydummy.MyData["object2"].search.side_effect = ["obj2"]
mydummy.MyData["object3"].search.side_effect = ["obj3"]
assert mydummy.getExample() == "obj1obj2obj3"
The above failed with run time error:
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/mock.py:1078: StopIteration
Here is the test that passed:
def test_get_dummy2():
dummy.MyData = MagicMock()
mydummy.MyData["object1"].search.side_effect = ["obj1", "obj2", "obj3"]
assert mydummy.getExample() == "obj1obj2obj3"
Am I missing something? I would have expected test_get_dummy1() to work and test_get_dummy2() to fail and not vice versa. Where and how can I find/learn more information about mocking to explain what is going on...
MyData["object1"] is converted to this function call: MyData.__getitem__("object1"). When you call your getExample method, the __getitem__ method is called 3 times with 3 parameters ("object1", "object2", "object3").
To mock the behavior you could have written your test like so:
def test_get_dummy_alternative():
mydummy.MyData = MagicMock()
mydummy.MyData.__getitem__.return_value.search.side_effect = ["obj1", "obj2", "obj3"]
assert mydummy.getExample() == "obj1obj2obj3"
Note the small change from your version: mydummy.MyData["object1"]... became: mydummy.MyData.__getitem__.return_value.... This is the regular MagicMock syntax - we want to to change the return value of the __getitem__ method.
BONUS:
I often struggle with mock syntax and understanding what's happening under the hood. This is why I wrote a helper library: the pytest-mock-generator. It can show you the actual calls made to the mock object.
To use it in your case you could have added this "exploration test":
def test_get_dummy_explore(mg):
mydummy.MyData = MagicMock()
mydummy.getExample()
mg.generate_asserts(mydummy.MyData, name='mydummy.MyData')
When you execute this test, the following output is printed to the console, which contains all the asserts to the actual calls to the mock:
from mock import call
mydummy.MyData.__getitem__.assert_has_calls(calls=[call('object1'),call('object2'),call('object3'),])
mydummy.MyData.__getitem__.return_value.search.assert_has_calls(calls=[call(),call(),call(),])
mydummy.MyData.__getitem__.return_value.search.return_value.__str__.assert_has_calls(calls=[call(),call(),call(),])
You can easily derive from here what has to be mocked.
I am trying to write pytest to test the following method by mocking the boto3 client. I tried with sample test case. I am not sure if that is right way to do it. Please correct me if I am wrong.
//temp.py
import boto3
import json
def temp_lambda(event):
client_lam = boto3.client('lambda', region_name="eu-west-1") #defined inside the function.
obj = client_lam.invoke(
FunctionName='XYZ',
InvocationType='ABC',
Payload=json.dumps({'payload': event}))
return obj
//test_temp.py
import mock
from unittest.mock import MagicMock, patch
from .temp import temp_lambda
#mock.patch("boto3.client")
def test_temp_lambda(mock_lambda_client):
mocked_response = MagicMock(return_value = 'yes')
mock_lambda_client.invoke.return_value = mocked_response.return_value
event = {}
x = temp_lambda(event)
assert x == 'yes'
I am getting assertion error in output
AssertionError: assert <MagicMock name='client().invoke()' id='2557742644480'> == 'yes'
def test_temp_lambda(context):
with patch('boto3.client') as mocked_response:
mocked= MagicMock()
mocked.invoke.return_value= "ok"
mocked_response.return_value=mocked
event = {}
x = temp_lambda(event)
assert response=='ok'
The golden rule of the mock framework is that you mock where the object is used not where it's defined.
So it would be #mock.patch('temp.boto3.client')
I have a really simple module like this:
def do(url):
try:
check(url)
foo(url)
except:
bar(url)
def check(url):
# some other stuff
if ' ' in url:
raise Exception('oops')
To unit test do I need to mock check, which would otherwise have some side effects.
from unittest.mock import patch
from main import do
def test_check_process():
with patch('main.check') as method:
do('http://something')
assert method.call_count == 1
My problem is that I also need the (mocked) check function to sometimes throw an exception. The patch function has the ability to provide a target via the new keyword, but when I change to patch the target function I get an error like AttributeError: 'function' object has no attribute 'call_count'.
def mock_checker(url):
if ' ' in url:
raise Exception('oops')
def test_check_process():
with patch('main.check', new=mock_checker) as method:
do('http://something')
assert method.call_count == 1
It seems like, when providing the new parameter, the patch context manager isn't a regular patch object and I can't spy on it at all.
How should I patch a function using the unittest module?
You defined a new mock_checker function, it's not mock object. The call_count property only exists on unittest.mock.Mock. We can use side_effect to raise an exception for the mock object.
E.g.
main.py:
def do(url):
try:
check(url)
foo(url)
except:
bar(url)
def check(url):
if ' ' in url:
raise Exception('oops')
def foo(url):
pass
def bar(url):
pass
test_main.py:
from unittest.mock import MagicMock, patch
from main import do
def test_check_process():
with patch('main.check', side_effect=Exception('oops')) as mock_check:
print(mock_check)
do('http://something')
assert mock_check.call_count == 1
def test_check_process_2():
mock_checker = MagicMock(side_effect=Exception('oops'))
with patch('main.check', new=mock_checker) as mock_check:
print(mock_check)
do('http://something')
assert mock_check.call_count == 1
if __name__ == '__main__':
test_check_process()
test_check_process_2()
The execution result:
<MagicMock name='check' id='4535123472'>
<MagicMock id='4535121168'>
Assert success
i have a function x in main.applications.handlers package
from main.config import get_db
def x(company_name):
db = get_db('my_db')
apps = []
for x in company_db.applications.find():
print(x)
apps.append(x)
return apps
now i want to write unittest for this method .
from unittest.mock import Mock,patch, MagicMock
#mock.patch('main.applications.handlers.get_db')
def test_show_applications_handler(self, mocked_db):
mocked_db.applications.find = MagicMock(return_value=[1,2,3])
apps = x('test_company') # apps should have [1,2,3] but its []
print(apps)
but company_db.applications.find() inside main.applications.handlers is not returning anything .it should return [1,2,3]
what could be wrong with this code?
Assuming that company_db is a typo and should be db, then to mock the return value of find(), you would do:
mocked_db.return_value.applications.find = MagicMock(return_value=[1,2,3])
mocked_db requires a return_value because get_db is called with the database name.
You could also drop the MagicMock and set the return_value of find directly:
mocked_db.return_value.applications.find.return_value = [1, 2, 3]