Reputation: 23
I am fairly new to Python and having a hard time wrapping my head around how to mock patch API calls in unit testing. FYI, I am using Python 2.7 and using nosetest for my unit testing needs.
I have the following module (myRedis.py) which I want to unit test:
import logging
import redis
redispool = None
class myRedis(object):
def __init__(self, redisHost, redisPort, redisDBNum):
if not redisPort.isdigit():
raise TypeError('Exception: Expected int for redisPort')
if not redisDBNum.isdigit():
raise TypeError('Exception: Expected int for redisDBNum')
self._redis_instance = None
self._redishost = redisHost
self._redisport = redisPort
self._redisdb = redisDBNum
global redispool
redispool = redis.ConnectionPool(host=self._redishost,
port=self._redisport,
db=self._redisdb)
def redis_connect(self):
LOGGER.info('Connecting Redis client to %s:%s:%s', self._redishost,
self._redisport, self._redisdb)
self._redis_instance = redis.StrictRedis(connection_pool=redispool)
def write_redis(self, key, value):
retval = self._redis_instance.set(key, value)
LOGGER.info('Writing data to redis (%s, %s). Retval=%s', key, value, retval)
return retval
def read_redis(self, key):
retval = self._redis_instance.get(key)
LOGGER.info('Reading data from redis: key=%s. Retval=%s', key, retval)
return retval
As far as unit testing goes, I have the following so far.
from nose.tools import *
import mock
from myRedis import myRedis
def setup():
pass
def teardown():
pass
@mock.patch('redis.StrictRedis')
def test_mock_redis_StrictRedis(mock_conn_pool):
mock_conn_pool.return_value = True
assert(True)
def test_myRedis():
assert_raises(TypeError, myRedis,
'test', '1234', 'a11')
assert_raises(TypeError, myRedis,
'test', 'a1234', '11')
myRedisObj = myRedis('localhost', '8888', '11')
assert_equal(myRedisObj._redishost, 'localhost')
assert_equal(myRedisObj._redisport, '8888')
assert_equal(myRedisObj._redisdb, '11')
myRedisObj.redis_connect()
#oclRedis.read_redis('test')
#oclRedis.write_redis('test', 'test')
I am able to patch the redis.StrictRedis() call without any problems. But how do I patch the redis' get() and set() calls since they are invoked on an object (_redis_instance in myRedis.py). I tried a few different versions of @mock.patch.object, but that didn't work for me. Looking for some guidance.
Thanks in advance.
Upvotes: 2
Views: 1049
Reputation: 2700
What you should patch are not the actual calls from your object but actually the object itself that those calls are invoking.
In your code it would something along the lines of:
from nose.tools import *
import mock
import unittest
from red import myRedis
def setup():
pass
def teardown():
pass
@mock.patch('redis.StrictRedis')
def test_mock_redis_StrictRedis(mock_conn_pool):
mock_conn_pool.return_value = True
assert(True)
def test_myRedis_wrong_args():
assert_raises(TypeError, myRedis,
'test', '1234', 'a11')
assert_raises(TypeError, myRedis,
'test', 'a1234', '11')
def test_myRedis_ok():
myRedisObj = myRedis('localhost', '8888', '11')
assert_equal(myRedisObj._redishost, 'localhost')
assert_equal(myRedisObj._redisport, '8888')
assert_equal(myRedisObj._redisdb, '11')
@mock.patch('redis.StrictRedis.set')
def test_myRedis_write(mock_strict_redis_set):
mock_strict_redis_set.return_value = {}
myRedisObj = myRedis('localhost', '8888', '11')
redis_connect = myRedisObj.redis_connect()
connect = myRedisObj.write_redis('1', '2')
assert connect == {}
As you can see I modified your tests to test one thing at a time. This is something that you generally want to do to avoid side-effects and guarantee test isolation.
Consider taking a look at the docs: https://docs.python.org/dev/library/unittest.mock.html
Finally indenting is key in Python, consider proper indenting in your code snippets going forward
Upvotes: 2