【问题标题】:Python injecting random number into testsPython将随机数注入测试
【发布时间】:2014-04-22 20:03:20
【问题描述】:

我写过这样的代码:

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)

我应该如何将自己的随机数注入测试?得到确定性的结果?

【问题讨论】:

  • 你到底想做什么?
  • 您可以传入rnd,但默认为None。然后在你的函数中只生成rnd,如果它是None。
  • 当你调用你的函数时,你可以做这样的事情 random.randrange(0000,9999)
  • 您是否考虑过使用例如random.seed(0) 重置为已知状态?
  • 问题的描述应该清楚地表明它是关于不是获取随机数据,而是为了获得确定性的东西......事实上,它具有误导性(我发现它正在寻找一种简单的方法来获取测试的随机数据

标签: python unit-testing testing random mocking


【解决方案1】:

Mockrandom.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)]))

【讨论】:

    【解决方案2】:

    您可以使用unittest.mock library 修补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)
    

    【讨论】:

      【解决方案3】:

      我想用完整的脚本改进响应,以便更好地理解和适应其他情况。

      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 3 次。这就是为什么您必须在 mock_random.side_effect 中放入相同或更多的项目。这是因为如果它的项目较少,它将引发StopIteration 错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-04
        • 2011-11-30
        • 2013-05-16
        • 2013-05-15
        • 2014-02-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多