2013-03-12 81 views
2

摘要:我正在做一个试验,尝试创建一个简单的模拟来替换redis。我试图做的事情应该从代码中显而易见。简短的版本是,模拟不起作用 - 它仍然会重新编写和创建密钥。Django模拟补丁不能正常工作,因为我期望

tests.py:

from django.test import TestCase 
import mock 
from redis_mock.simple_redis_mock import redisMockGetRedis, redisMockFlushDB 
from account.util import get_redis 

class SimpleTest(TestCase): 

    def setUp(self): 
     redisMockFlushDB() 

    @mock.patch("account.util.get_redis", redisMockGetRedis) 
    def test_redis(self): 
     key = "hello123" 
     value = "world123" 
     r = get_redis() 
     r.set(key, value) 
     value2 = r.get(key) 
     self.assertEqual(value, value2) 

util.py:

import redis 

REDIS_HOST = 'localhost' 
REDIS_PORT = 6379 
REDIS_DEFAULT_DB = 0 

def get_redis(): 
    print "account.util.get_redis" 
    return redis.StrictRedis(
     REDIS_HOST, 
     REDIS_PORT, 
     REDIS_DEFAULT_DB 
    ) 

simple_redis_mock.py:

""" 
A simple mock for Redis. Just mocks set, get and expire commands. 
""" 

class SimpleRedisMockDB: 
    db = {} 

def redisMockFlushDB(): 
    """ 
    Helper function to flush the RedisMock db between test runs 
    """ 
    print "redisMockFlushDB" 
    SimpleRedisMock.db = {} 

class SimpleRedisMock: 
    def get(self, key): 
     val = None 
     try: 
      val = SimpleRedisMockDB.db[key] 
     except: 
      pass 
     print "SimpleRedisMock get(" + str(key) + "):" + str(val) 
     return val 

    def set(self, key, val): 
     print "SimpleRedisMock set(" + str(key) + "," + str(val) +")" 
     SimpleRedisMockDB.db[key] = val 

    def expire(self, key): 
     pass 


def redisMockGetRedis(): 
    print "redisMockGetRedis" 
    return SimpleRedisMock() 

现在,我想到的是,当我运行我的测试,没有设置redis键。这里是实际发生的事情:

twang$ redis-cli 
redis 127.0.0.1:6379> del hello123 
(integer) 1 
redis 127.0.0.1:6379> exit 
twang$ ./manage.py test account 
Creating test database for alias 'default'... 
redisMockFlushDB 
account.util.get_redis 
. 
---------------------------------------------------------------------- 
Ran 1 test in 0.001s 

OK 
Destroying test database for alias 'default'... 
twang$ redis-cli 
redis 127.0.0.1:6379> get hello123 
"world123" 

简单的问题:为什么不是mock.patch做我期望的?

+0

可能重复的[Python模拟修补程序无法正常工作,因为公共方法](https://stackoverflow.com/questions/30987973/python-mock-patch-doesnt-work-as-expected-for-public -方法) – 2017-05-24 21:15:17

回答

7

修补程序只会模拟您修补它的位置中的对象。示例代码的一小部分应该有助于解释发生了什么。

from mock import Mock, patch 
import unittest 

from patch_code import anotherfunc, thefunc 

print 'Function imported', thefunc 

class SomeTest(unittest.TestCase): 

    @patch('patch_code.thefunc', Mock()) 
    def test_method(self): 
     anotherfunc() 
     print 'Inside test method', thefunc 


if __name__ == '__main__': 
    unittest.main() 

和被测代码仅仅是两个功能:

def thefunc(): 
    pass 

def anotherfunc(): 
    print 'Inside code under test', thefunc 

运行该测试给出了下面的输出

Function imported <function thefunc at 0xb740e614> 
Inside code under test <Mock id='3071597132'> 
Inside test method <function thefunc at 0xb740e614> 

你可以清楚地看到,该补丁已经嘲笑的唯一的地方'thefunc'在测试中的代码中。

如果你想测试功能get_redis而不引起任何副作用,那么你应该嘲笑account.util.redis.StrictRedis并断言它被调用了正确的参数。

如果你想测试使用get_redis,那么你应该模拟出get_redis,并导入使用get_redis的功能,并在您的测试呼叫功能功能。