2013-03-12 181 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的功能,並在您的測試呼叫功能功能。