在单元测试中模拟API调用

时间:2017-03-15 19:31:55

标签: python unit-testing mocking

我对Python很陌生,并且很难解决如何在单元测试中模拟补丁API调用的问题。 仅供参考,我正在使用Python 2.7并使用nosetest来满足我的单元测试需求。

我有以下模块(myRedis.py),我想进行单元测试:

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

就单元测试而言,到目前为止我有以下内容。

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')

我能够毫无问题地修补redis.StrictRedis()调用。但是我如何修补redis的'get()和set()调用,因为它们是在对象上调用的(myRedis.py中的_redis_instance)。我尝试了几个不同版本的@ mock.patch.object,但这对我不起作用。寻求一些指导。

提前致谢。

1 个答案:

答案 0 :(得分:2)

你应该修补的不是你对象的实际调用,而是实际调用这些调用的对象本身。

在你的代码中,它将成为:

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 == {}

如您所见,我修改了您的测试以一次测试一件事。这是您通常希望做的事情,以避免副作用并保证测试隔离。

请考虑查看文档:{​​{3}}

最后缩进是Python中的关键,考虑在你的代码片段中进行适当的缩进