Django模拟补丁不能像我期望的那样工作

use*_*081 2 python django unit-testing mocking redis

简介:我正在尝试创建一个简单的模拟来替换redis.从代码中可以明显看出我要做的事情.简短的版本是,模拟不起作用 - 它仍然是redis和创建密钥.

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)
Run Code Online (Sandbox Code Playgroud)

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
    )
Run Code Online (Sandbox Code Playgroud)

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()
Run Code Online (Sandbox Code Playgroud)

现在,我期望的是,当我运行测试时,没有设置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"
Run Code Online (Sandbox Code Playgroud)

简单的问题:为什么不执行mock.patch做我期望的事情?

小智 10

链接

http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch

帮助我更好地理解如何在python中修补函数调用.


ayc*_*dee 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()
Run Code Online (Sandbox Code Playgroud)

而且测试中的代码只有两个功能:

def thefunc():
    pass

def anotherfunc():
    print 'Inside code under test', thefunc
Run Code Online (Sandbox Code Playgroud)

运行该测试会得到以下输出

Function imported <function thefunc at 0xb740e614>
Inside code under test <Mock id='3071597132'>
Inside test method <function thefunc at 0xb740e614>
Run Code Online (Sandbox Code Playgroud)

你可以清楚地看到补丁模拟'thefunc'的唯一地方是在被测试的代码中.

如果你想测试函数get_redis而不会产生任何副作用,那么你应该模拟account.util.redis.StrictRedis并声明它是用正确的参数调用的.

如果你想测试使用的 函数,get_redis你应该模拟出来get_redis,导入使用get_redis的函数,并在测试中调用函数.