如何在python中模拟random.choice?

时间:2016-10-08 08:16:33

标签: python unit-testing mocking

我希望每次在我的unittest中choice都返回相同的值1000。以下代码无效。

import unittest
from random import choice

from mock import mock

def a():
    return choice([1, 2, 3])

class mockobj(object):
    @classmethod
    def choice(cls, li):
        return 1000

class testMock(unittest.TestCase):

    def test1(self):
        with mock.patch('random.choice', mockobj.choice):
            self.assertEqual(a(), 1000)

错误消息如下:

Failure
Traceback (most recent call last):
  File "test.py", line 15, in test1
    self.assertEqual(a(), 1000)
AssertionError: 3 != 1000

我应该如何修改它才能使其正常工作?我使用的是python2.7

2 个答案:

答案 0 :(得分:8)

此处的问题是a()正在使用random.choice未修补版本。

比较函数ab

import random
from random import choice

def a():
    return choice([1, 2, 3])

def b():
    return random.choice([1, 2, 3])

def choice1000(values):
    return 1000

import unittest.mock as mock

with mock.patch('random.choice', choice1000):
    print('a', a())
    print('b', b())

打印例如:

a 3
b 1000

为什么?

这一行是问题所在:

from random import choice

导入random而不是存储random.choice到名为choice的新变量。

稍后,mock.patch修补了原始random.choice,但没有修补本地choice

我可以修补当地的吗?是:

with mock.patch('__main__.choice', choice1000):
    print('a', a())
    print('b', b())

现在它打印出来。

a 1000
b 1

(我使用'__main__',因为我将此代码放入top-level file - 在您的情况下可能是其他内容)

那该怎么办?

要么修补所有内容,要么采取不同的方法。例如,修补程序a()而不是choice()

替代解决方案

在这种情况下,如果您要测试random函数的行为,最好使用seed

def a():
    return random.choice([1, 2, 3, 1000])

def test1(self):
    random.seed(0)
    self.assertEqual(a(), 1000)

您无法事先知道将为某个种子生成哪些随机值,但您可以确定它们将始终相同。这正是您在测试中所需要的。

在上面的最后一个例子中,我在a()之后测试random.seed(0)一次并返回1000,所以我确信它每次都会这样做:

>>> import random
>>> random.seed(0)
>>> print (random.choice([1, 2, 3, 1000]))
1000
>>> random.seed(0)
>>> print (random.choice([1, 2, 3, 1000]))
1000
>>> random.seed(0)
>>> print (random.choice([1, 2, 3, 1000]))
1000
>>> random.seed(0)
>>> print (random.choice([1, 2, 3, 1000]))
1000

答案 1 :(得分:7)

我不知道测试中的mockobj是什么,但你可以做的是。

    @mock.patch('random.choice')
    def test1(self, choice_mock):
        choice_mock.return_value = 1000
        self.assertEqual(a(), 1000)