Reg*_*lva 11 python random unit-testing
如何使用随机值验证单元测试?我需要保证gen_age返回15到99之间的整数,但此代码不正确.
import random
import unittest
def gen_age():
# generate integer between 15 and 99
return random.randint(15, 99)
class AgeTest(unittest.TestCase):
def setUp(self):
self.a = gen_age()
def test_choice(self):
element = random.choice(self.a)
self.assertTrue(element in self.a)
def test_sample(self):
for element in random.sample(self.a, 98):
self.assertTrue(element in self.a)
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
use*_*716 16
测试类似行为的最佳方法是将种子设置为Random对象.
随机包提供Random类.随机实例具有与随机包相同的方法; random(),randint(),sample(),...此外,Random接受种子.向Random添加种子使其输出确定性.例如,
from random import Random
random = Random(666)
assert random.randint(0, 1000) == 467 # will never break
Run Code Online (Sandbox Code Playgroud)
因此,您希望将您的功能测试为
from random import Random
import unittest
random = Random()
def gen_age():
# generate integer between 15 and 99
return random.randint(15, 99)
class AgeTest(unittest.TestCase):
def setUp(self):
global random
random = Random(666)
def test_gen_age(self):
self.assertEqual(gen_age(), 53)
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
请注意,如果您的测试不在同一个文件中,则需要使用随机修补unittest.mock.patch.这样的事情应该有效
from random import Random
from package.file import gen_age
import unittest
class AgeTest(unittest.TestCase):
def setUp(self):
self.random = Random(666)
@patch('package.file.random')
def test_gen_age(self, random):
random.randint._mock_side_effect = self.random.randint
self.assertEqual(gen_age(), 53)
Run Code Online (Sandbox Code Playgroud)
小智 5
我认为在 @user983716 的答案之上还有更多内容可以构建,因为:
真正的愿望不是测试 的功能Random.randint,而是输出是否正确。这是@rufanov 建议的,尽管该解决方案可以改进。
在整个答案中,我们假设实现package.file与测试是分开的。
让我们从以下内容开始:
import unittest
from package.file import get_age
class AgeTest(unittest.TestCase):
def test_gen_age_generates_a_number_between_15_and_99(self):
age = gen_age()
self.assertGreaterEqual(age, 15)
self.assertLessEqual(age, 99)
Run Code Online (Sandbox Code Playgroud)
这是一个很好的开始测试,因为如果发生故障它会提供清晰的输出:
AssertionError: 14 not greater than or equal to 15
AssertionError: 100 not less than or equal to 99
Run Code Online (Sandbox Code Playgroud)
好的,但我们还想确保它是一个随机数,因此我们可以添加另一个测试来确保我们按randint预期获得它:
AssertionError: 14 not greater than or equal to 15
AssertionError: 100 not less than or equal to 99
Run Code Online (Sandbox Code Playgroud)
我们在这里做了两件重要的事情:
random(来自定义的文件gen_age)被修补,以便我们可以对其进行测试,而不必依赖于实际的实现randint,以便给出正确的范围可以编写额外的测试来断言实际返回值,确认给定的数字始终是随机的。这将提供该方法直接返回随机值的信心,因为可以想象该方法可以执行更多操作,甚至返回一些任意值,即使它在内部仍然进行调用randint。
例如,假设某人进行了gen_age()如下更改:
@unittest.mock.patch('package.file.random')
def test_gen_age_gets_a_random_integer_in_the_range(self, mock_random):
gen_age()
mock_random.randint.assert_called_with(15, 99)
Run Code Online (Sandbox Code Playgroud)
呃哦,现在只有那些randint返回 99 的情况我们的第一个测试才会失败,而第二个测试仍然会通过。这是一个等待发生的生产错误......
那么,确认结果的简单但有效的方法可能如下:
def gen_age():
age = random.randint(15, 99) # still doing what we're looking for
return age + 1 # but now we get a result of 16-100
Run Code Online (Sandbox Code Playgroud)
不过,这里还有最后一个缺陷......如果返回的值更改为:
@unittest.mock.patch('package.file.random')
def test_returns_age_as_generated(mock_random):
mock_random.return_value = 27
age = get_age()
self.assertEqual(age, 27)
Run Code Online (Sandbox Code Playgroud)
现在所有测试都通过了,但我们仍然没有得到我们真正想要的随机结果。为了解决这个问题,我们还需要随机化测试值......
事实证明,我们的源代码指向了答案 - 只需使用真正的实现作为第二次测试的一部分即可。为此,我们首先需要导入原始文件random:
def gen_age():
age = random.randint(15, 99)
return 27
Run Code Online (Sandbox Code Playgroud)
然后我们将修改我们编写的最后一个测试,结果如下:
from package.file import get_age, random
Run Code Online (Sandbox Code Playgroud)
因此,我们最终将得到以下全套测试:
@unittest.mock.patch('package.file.random')
def test_returns_age_as_generated(mock_random):
random_age = random.randint(15, 99)
mock_random.randint.return_value = random_age
age = get_age()
self.assertEqual(age, random_age)
Run Code Online (Sandbox Code Playgroud)