I'm learning unittest
and unittest.mock
, and struggling with the concepts and implementations primarily with mock
.
For context, what I'm playing with is a Django / DRF API and Redis. I'm trying to write tests which require mocking the Redis calls.
Here is the test I'm working on:
# tests.py
import unittest
from unittest.mock import patch
from core.views import KeysViewSet
class KeysViewSetTestCase(unittest.TestCase):
def setUp(self):
self.json_object = {'key': 'hello', 'value': 'world'}
self.view = KeysViewSet()
def test_create(self):
with patch('core.views.RedisUtil.create') as mocked_create:
mocked_create.return_value.data = True
created = self.view.create(self.json_object)
The views.py
:
# viefws.py
# Third party imports
from rest_framework import status, viewsets
from rest_framework.response import Response
# Croner imports
from .serializers import KeysSerializer
# Import Redis
from .utils import RedisUtil
class KeysViewSet(viewsets.ViewSet):
"""
METHOD URI DESCRIPTION
GET /api/keys/<:key>/ Returns specific value from key
POST /api/keys/ Creates a new key/value
DELETE /api/keys/<:key>/ Deletes a specific key
"""
def __init__(self, *args, **kwargs):
"""
Instantiate the RedisUtil object.
"""
self.redis_util = RedisUtil()
def create(self, request):
"""
Creates a key/pair in the Redis store.
"""
print(request)
# Serialize the request body
serializer = KeysSerializer(data=request.data)
# If valid, create the key/value in Redis; if not send error message
if serializer.is_valid():
return Response(self.redis_util.create(serializer.data))
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
And the utils.py
that handles the Redis actions:
# utils.py
# Django imports
from django.conf import settings
# Redis imports
import redis
class RedisUtil:
"""
Instantiates the Redis object and sets the connection params.
"""
def __init__(self):
self.redis_instance = redis.StrictRedis(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT
)
def create(self, data):
"""
Creates the key/value pair from request body.
"""
return self.redis_instance.set(data['key'], data['value'])
The error I'm getting is the following:
Found 1 test(s).
System check identified no issues (0 silenced).
{'key': 'hello', 'value': 'world'}
E
======================================================================
ERROR: test_create (core.tests.KeysViewSetTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/cjones/Projects/test/kv-store/api/src/core/tests.py", line 19, in test_create
created = self.view.create(self.json_object)
File "/Users/cjones/Projects/test/kv-store/api/src/core/views.py", line 32, in create
serializer = KeysSerializer(data=request.data)
AttributeError: 'dict' object has no attribute 'data'
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
I know what I'm getting this error: the KeysViewSet().create()
in views.py
is expecting the object I'm passing to be at request.data = {}
and it isn't.
Resolving it is what I'm trying to figure out.
I know there is the request
library, but not sure I would need to import it just for this. DRF has several options including APIRequestFactory, but those will try to spin up a database and create an error as it will try to connect to Redis which it won't be able to.
How should I go about resolving this issue?
What I ended up doing to resolve the issue was the following:
# test.py
import unittest
from unittest.mock import patch
from core.views import KeysViewSet
class KeysViewSetTestCase(unittest.TestCase):
def setUp(self):
self.json_object = {'key': 'hello', 'value': 'world'}
self.view = KeysViewSet()
class Request:
def __init__(self, data):
self.data = data
self.request = Request(self.json_object)
def test_create(self):
with patch('core.views.RedisUtil.create') as mocked_create:
mocked_create.return_value.data = True
created = self.view.create(self.request)
That being said, I'm not sure that this is a desirable solution so I'm reluctant to accept it as the correct answer. Looking forward to feedback.