我希望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
这里的问题是a()
使用的是未打补丁的版本的random.choice
。
比较a
和b
函数:
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__'
,因为我把这段代码放在顶层文件中——在您的情况下,它可能是别的东西)
那么该怎么办呢?
要么修补一切,要么采取不同的方法。例如,将choice()
替换为a()
。
在这种情况下,如果您想测试random
函数的行为,最好使用种子
def a():
return random.choice([1, 2, 3, 1000])
def test1(self):
random.seed(0)
self.assertEqual(a(), 1000)
你不能事先知道某个种子会生成什么随机值,但你可以确定它们总是相同的。这正是你在测试中需要的。
在上面的最后一个例子中,我在random.seed(0)
之后测试了a()
一次,它返回了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
标题>标题>我不知道什么是mockobj从测试,但你可以做的是。
@mock.patch('random.choice')
def test1(self, choice_mock):
choice_mock.return_value = 1000
self.assertEqual(a(), 1000)
我想用一个完整的脚本来改进@Alex响应,以便更好地理解和适应其他情况。
import random
from unittest import TestCase, mock
letters = ['A', 'B', 'C', 'D']
def get_random_words(): # Simple function using choice
l = []
for _ in range(3):
l.append(random.choice(letters))
return "".join(l)
class TestRandom(TestCase):
@mock.patch('random.choice') # *(1)
def test_get_random_words(self, mock_choice):
mock_choice.side_effect = ['A','b','D','Z'] # *(2)
result = get_random_words()
self.assertEqual(result, 'AbD', 'Does not generate correct string')
<标题> 考虑*(1)在本例中,该函数位于同一文件中,但如果它位于另一个文件中,则必须更改补丁的路径例:@mock.patch('your_package.your_file.your_function.random.choice')
*(2)在这种情况下,get_random_words
函数调用random.choice
3次。这就是为什么必须在mock_choice.side_effect
中放入相等或更多的项。这是因为如果它有更少的项目,它将抛出StopIteration
错误。