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.
CodePudding user response:
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
