Python 在测试中注入随机数

1 投票
3 回答
3635 浏览
提问于 2025-04-17 22:40

我写了这样的代码:

def choice(states):
    states = list(states)
    rnd = random.random()
    for state, p in states:
        rnd -= p
        if rnd <= 0:
            return state

现在我需要创建一些测试:

import unittest
class Tests(unittest.TestCase):
    def test_choice(self):
        assertEquals(choice(states),something_equl)

我该怎么把我自己的随机数字放进测试里,以便得到可重复的结果呢?

3 个回答

0

我想通过一个完整的脚本来改善这个回应,这样可以更好地理解并适应其他情况。

import random
from unittest import TestCase, mock


def get_random_words(): # Simple function using choice
  l = []
  for _ in range(3):
      l.append(random.random(0, 10))
    
  return "".join([str(n) for n in l])

class TestRandom(TestCase):

   @mock.patch('random.random') # *(1)
   def test_get_random_words(self, mock_random):
    
      mock_random.side_effect = [1,7,3,6] # *(2)
      result = get_random_words()
    
      self.assertEqual(result, '173', 'Does not generate correct numbers')

注意事项

*(1) 在这个例子中,函数是在同一个文件里的,但如果它在另一个文件中,你需要更改路径。例如:@mock.patch('your_package.your_file.your_function.random.random')

*(2) 在这个案例中,get_random_words 函数调用了 random.random 三次。所以你需要在 mock_random.side_effect 中放入相同数量或更多的项目。如果放的项目少了,就会出现 StopIteration 错误。

4

你可以使用unittest.mock来替换掉random()这个函数。这个库是从Python 3.3版本开始就有的,如果你用的是旧版本,可以单独安装mock

try:
    from unittest import mock
except ImportError:
    import mock

class Tests(unittest.TestCase):
    @mock.patch('random.random')
    def test_choice(self, mock_random):
        mock_random.return_value = 0.42
        assertEquals(choice(states),something_equl)
6

这里是关于如何“模拟”random.random()这个函数的内容,简单来说,就是在测试的时候用一个假的版本来代替它。这样做的好处是可以控制输出,让测试变得更简单。下面是一个例子:

import random
import unittest
import mock


def choice(states):
    states = list(states)
    rnd = random.random()
    for state, p in states:
        rnd -= p
        if rnd <= 0:
            return state


class Tests(unittest.TestCase):
    @mock.patch('random.random')
    def test_first_state_fires(self, random_call):
        random_call.return_value = 1
        self.assertEquals(choice([(1, 1)]), 1)

    @mock.patch('random.random')
    def test_returns_none(self, random_call):
        random_call.return_value = 2
        self.assertIsNone(choice([(1, 1)]))

撰写回答