I am trying to mock the return of db.collection.find to avoid database calls. I tried to create a mock.patch for mongoclient() and attached on it a return_value. But when my_call() call db.collection.find it just return a Mock Object. Somebody have a idea how mock it?
#dao.py
class MyDao():
def my_call():
db = mongoclient().db_name
result = db.collection.find()
return result
#test_dao.py
import dao
def test_my_call():
result = dao.my_call()
assert result == list()
I think it would help to see your current mock to edit. In general, this is how I would mock the pymongo collection.find() as a standalone function.
test_dao.py
import unittest
import mock
from mock import Mock
import pymongo
class Test_Dao(unittest.TestCase):
"""
Set up the mock
"""
#classmethod
#mock.patch('pymongo.collection')
def setUpClass(self, mock_mongo):
a = Mock()
a.find.side_effect = self.findResponse # Assign side effect for mocked method
mock_mongo.return_value = a # Importing pymongo.collection returns the mock
"""
Response Data
"""
findResponse = 'some data'
def test_my_call():
result = dao.my_call()
assert result == list()
...
In your case that is worth a try but might not work because you are calling collection.find() from a variable.
You may need to mock the MongoClient() such that db_name has a side_effect to return a fake class. Then the fake class would need a collection.find() method you define. That would be a little longer and look a little bit like this:
class FakeCollection:
def find:
return 'data'
class FakeDatabase:
def collection:
return FakeCollection()
...
#classmethod
#mock.patch('pymongo.MongoClient')
def setUpClass(self, mock_mongo):
a = Mock()
a.db_name.side_effect = self.dbResponse
mock_mongo.return_value = a
dbResponse = FakeDatabase()
Related
I am using mockito to unit test a program in Python. I have a class like:
import boto3
import datetime
class Cache:
def __init__(self):
client = boto3.resource('s3')
self.bucket_name = 'name'
self.bucket = client.Bucket(self.bucket_name)
def setup_cache(self, cache_file='cache.csv', cache_filepath='cache'):
cache_object = self.bucket.Object(cache_file)
if cache_object.last_modified < datetime.datetime.now():
self.bucket.download_file(cache_filepath, cache_file)
else:
print('Cache already up to date')
def main():
cache = Cache()
cache.setup_cache()
And the test code I am getting stuck on is this:
from mockito import mock, when
import datetime
import boto3
import mock_cache
class TestMockCache:
def test_last_mod(self):
mock_client = mock()
when(boto3).resource('s3').thenReturn(mock_client)
mock_bucket = mock()
when(mock_client).Bucket('name').thenReturn(mock_bucket)
mock_bucket.last_modified = datetime.datetime.now()
mock_cache.main()
When running pytest on the unit test, I am getting thrown this attribute error:
AttributeError: 'NoneType' object has no attribute 'last_modified'
From the documentation it looked like I could assign 'cache_mock.last_modified' like this. However, I also tried:
when(cache_mock).last_modified.thenReturn(test_date)
and got:
AttributeError: 'StubbedInvocation' object has no attribute 'thenReturn'
Which I don't fully understand, but assume that means a mockito mock() object can't have multiple return values?
Any help with this would be appreciated. I feel like I am misunderstanding something fundamental about either how mockito's mock works or mocking in general.
The patch from the Mock can be used to mock the client from boto3. Do not have to return anything from the client, as it is being mocked on the whole.
e.g.:
from folder.file import your_func
from unittest.mock import patch
class TestSomething(unittest.TestCase):
#patch("botocore.client.BaseClient._make_api_call")
def test_something(self, _mock_client_boto3):
your_func()
.. do something
In case you want to return something from the client, it could be achieved by specifying the return_value in the patch as shown below:
from folder.file import your_func
from unittest.mock import patch
class TestSomething(unittest.TestCase):
#patch("botocore.client.BaseClient._make_api_call", return_value=None)
def test_something(self, _mock_client_boto3):
your_func()
.. do something
I have a class ProductionClass with a method method_to_test which I want to test. Class ProductionClass has dependency to api, which I want to mock in the test.
from my_module.apis import api
class ProductionClass:
def method_to_test:
data = api.method_to_mock()
api.method_to_check_call(data)
The test code is as follows:
For api I have a mock class MockApi that I use by refering to it in the #patch decorator.
from unittest.mock import patch, MagicMock
class MockApi:
def method_to_mock():
return some_mock_data
def method_to_check_call(data):
pass
class TestClass:
#patch('my_module.apis.api', MagicMock(return_value=MockApi()))
def test_check_called_with(self):
from module_of_class_production_class.ProductionClass import method_to_test
mock_api = MockApi()
method_to_test()
some_data = { ... }
mock.method_to_check_call.assert_called_with(some_data)
The problem is that it does not work because mock_api is not the same instance of MockApi that is provided in the #patch decorator. Is there a better way to test that?
I have not tested this, but I think that your patch object will get passed as first argument to test_check_called_with like so:
#patch('my_module.apis.api', MagicMock(return_value=MockApi()))
def test_check_called_with(self, your_magic_mock):
# Rest of code
You can also use the with construct like so:
def test_check_called_with(self):
my_api = MockApi()
with patch('my_module.apis.api', MagicMock(return_value=my_api)) as my_mock_api:
# Your code here
You can checkout the official python documentation here for more details: https://docs.python.org/3/library/unittest.mock.html#quick-guide
Hello I am pretty new to unit testing and therefore I got a big issue with unittest.mock.
My Project consists of different modules.
My first module is General:
general.py
def do_something(item, collection):
# some more code that i want to test
try:
collection.insert_one(item)
except:
print("did not work")
My second module ist my_module.py
mymodule.py
import general
from pymongo import MongoClient
client = MongoClient("localhost", 27017)
db = client['db']
collection = db['col']
item =
{
"id": 1
}
def method:
general.do_something(item, collection)
Now I want to test the do_something(item, collection) method from general.py, and therefore I want to mock the collection.insert_one(item). I did not find a possible solution for this.
I tried it with patch, but my Problem is, that the parameter collection (which is a pymongo Collection) is a parameter that calls a function. How can i now manage to mock collection.insert_one?
My target is to extract collection.insert_one and set a MagicMock into it. And this Magic Mock should have the possibility to crash to check if the except part works or to not crash to check if the try part workes.
TestGeneral.py
import unnittest
class TestGeneral(unittest.TestCase):
#patch()
def test_general():
Thank you in advance! :)
You don't actually need a mock here, you could just create a class that has a similar functionality.
TestGeneral.py
import unnittest
class TestGeneral(unittest.TestCase):
def test_general_success():
assert general.do_something(collection(), None)
def test_general_failure():
with self.assertRaises(Exception):
general.do_something(collection(fail=True), None))
class collection:
def __init__(self, fail=False):
self.fail = fail
def insert_one(self, item):
if self.fail:
raise Exception
return True
Then you can also check the stdout to make sure a print is used on success
If you had to use mock for some reason, this method could work
TestGeneral.py
import unnittest
class TestGeneral(unittest.TestCase):
#mock.patch('{your path}.my_module.MongoClient')
def test_general_success(mock_mongo):
mock_mongo.return_value = {'db': None, 'col': collection()}
assert general.do_something(None, None) # None here since the collection is mocked anyway
#mock.patch('{your path}.my_module.MongoClient')
def test_general_failure(mock_mongo):
mock_mongo.return_value = {'db': None, 'col': collection(fail=True)}
with self.assertRaises(Exception):
general.do_something(None, None))
class collection:
def __init__(self, fail=False):
self.fail = fail
def insert_one(self, item):
if self.fail:
raise Exception
return True
The downside to this is that you have now mocked the entire MongoDB, meaning any other uses of it (i.e client) will also be mocked
I am looking for a magic method similar to the __get__ method, but in my case the variable is not inside another class, I want something like:
class A(object):
def __similar_to_get__(self):
print 'called'
return self
a = A()
b = a
>>> 'called'
Is it possible?
The reason I am asking this is, I am using a python mock library, let's say a function I am testing uses URI attribute, and I want to mock it to return different values in subsequent calls. Eg:
class WebService(obj):
URI = 'http://works.com'
def dowork(self):
call_api(self.URI)
For me to mock a failure I am using the mock library:
mock = MagicMock()
mock.side_effect = ['http://fail.com', 'http://works.com']
with patch('WebService.URI', mock):
# do the testing
But the problem is I can only get mock to return the urls by calling the callable mock() not just simply accessing mock
PS: I am a mock noob.
Not directly answering my own question, I managed to use a property to work around this:
from dps.px.pxpost import PxPost
mock = MagicMock()
mock.side_effect = ['http://doesnotexist', PxPost.URI]
def URI(self):
return mock()
with patch('django.conf.settings.CELERY_ALWAYS_EAGER', True, create=True):
with patch('dps.px.pxpost.PxPost.URI', property(URI)):
self.transaction.process()
for sub_transaction in self.transaction.sub_transactions.all():
self.assertTrue(isinstance(sub_transaction.state, CompletedSubTransaction))
self.assertTrue(sub_transaction.transaction_logs.count() > 0)
self.assertTrue(isinstance(self.transaction.state, CompletedTransaction))
I am using mock with Python and was wondering which of those two approaches is better (read: more pythonic).
Method one: Just create a mock object and use that. The code looks like:
def test_one (self):
mock = Mock()
mock.method.return_value = True
self.sut.something(mock) # This should called mock.method and checks the result.
self.assertTrue(mock.method.called)
Method two: Use patch to create a mock. The code looks like:
#patch("MyClass")
def test_two (self, mock):
instance = mock.return_value
instance.method.return_value = True
self.sut.something(instance) # This should called mock.method and checks the result.
self.assertTrue(instance.method.called)
Both methods do the same thing. I am unsure of the differences.
Could anyone enlighten me?
mock.patch is a very very different critter than mock.Mock. patch replaces the class with a mock object and lets you work with the mock instance. Take a look at this snippet:
>>> class MyClass(object):
... def __init__(self):
... print 'Created MyClass#{0}'.format(id(self))
...
>>> def create_instance():
... return MyClass()
...
>>> x = create_instance()
Created MyClass#4299548304
>>>
>>> #mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
... MyClass.return_value = 'foo'
... return create_instance()
...
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
... print MyClass
... return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass#4300234128
<__main__.MyClass object at 0x100505d90>
patch replaces MyClass in a way that allows you to control the usage of the class in functions that you call. Once you patch a class, references to the class are completely replaced by the mock instance.
mock.patch is usually used when you are testing something that creates a new instance of a class inside of the test. mock.Mock instances are clearer and are preferred. If your self.sut.something method created an instance of MyClass instead of receiving an instance as a parameter, then mock.patch would be appropriate here.
I've got a YouTube video on this.
Short answer: Use mock when you're passing in the thing that you want mocked, and patch if you're not. Of the two, mock is strongly preferred because it means you're writing code with proper dependency injection.
Silly example:
# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
sentence.replace('cks','x') # We're cool and hip.
twitter_api.send(sentence)
# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
twitter_api = Twitter(user="XXX", password="YYY")
sentence.replace('cks','x')
twitter_api.send(sentence)
Key points which explain difference and provide guidance upon working with unittest.mock
Use Mock if you want to replace some interface elements(passing args) of the object under test
Use patch if you want to replace internal call to some objects and imported modules of the object under test
Always provide spec from the object you are mocking
With patch you can always provide autospec
With Mock you can provide spec
Instead of Mock, you can use create_autospec, which intended to create Mock objects with specification.
In the question above the right answer would be to use Mock, or to be more precise create_autospec (because it will add spec to the mock methods of the class you are mocking), the defined spec on the mock will be helpful in case of an attempt to call method of the class which doesn't exists ( regardless signature), please see some
from unittest import TestCase
from unittest.mock import Mock, create_autospec, patch
class MyClass:
#staticmethod
def method(foo, bar):
print(foo)
def something(some_class: MyClass):
arg = 1
# Would fail becuase of wrong parameters passed to methd.
return some_class.method(arg)
def second(some_class: MyClass):
arg = 1
return some_class.unexisted_method(arg)
class TestSomethingTestCase(TestCase):
def test_something_with_autospec(self):
mock = create_autospec(MyClass)
mock.method.return_value = True
# Fails because of signature misuse.
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_something(self):
mock = Mock() # Note that Mock(spec=MyClass) will also pass, because signatures of mock don't have spec.
mock.method.return_value = True
result = something(mock)
self.assertTrue(result)
self.assertTrue(mock.method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
class TestSecondTestCase(TestCase):
def test_second_with_autospec(self):
mock = Mock(spec=MyClass)
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second_with_patch_autospec(self):
with patch(f'{__name__}.MyClass', autospec=True) as mock:
# Fails because of signature misuse.
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
def test_second(self):
mock = Mock()
mock.unexisted_method.return_value = True
result = second(mock)
self.assertTrue(result)
self.assertTrue(mock.unexisted_method.called)
The test cases with defined spec used fail because methods called from something and second functions aren't complaint with MyClass, which means - they catch bugs, whereas default Mock will display.
As a side note there is one more option: use patch.object to mock just the class method which is called with.
The good use cases for patch would be the case when the class is used as inner part of function:
def something():
arg = 1
return MyClass.method(arg)
Then you will want to use patch as a decorator to mock the MyClass.