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