3 回答
TA贡献1829条经验 获得超9个赞
是的,假设听起来是个好方法。例如:
from unittest import TestCase
from hypothesis import given
from hypothesis.strategies import integers
import hypothesis_random as undertest
class Test(TestCase):
@given(seed=integers())
def test_uses_random(self, seed):
undertest.uses_random(seed)
如果您的函数引发错误,您将获得异常的回溯和来自假设的伪造示例,该示例触发它作为测试的输出,例如
Falsifying example: test_uses_random(
self=<test_hypothesis_random.Test testMethod=test_uses_random>, seed=-43,
)
Error
Traceback (most recent call last):
...
TA贡献1864条经验 获得超6个赞
假设对于您的用例来说是一种极好的可能性——如果您使用得当的话。首先,为什么它有效:它不是随机的,而是伪随机的。当一个复杂示例的测试失败时,它会降低复杂性,直到找到失败的最小测试用例,然后给你那个。然后它还存储失败测试用例的数据库,因此重放旧失败是它尝试的第一件事。
现在,缺点是构建测试用例通常需要很长时间,但好处是您可以真正确定您的代码是健壮的。
我不知道你的代码是什么样的,只是为了给你一个模型:
from hypothesis import strategies as st
from hypothesis import assume
# In this example, damage and miss chance are based
# on the length of the name of the attack
samus = Character(health=100, attacks=['punch', 'shoot'])
wario = Character(health=70, attacks=['growl', 'punch'])
bowser = Character(health=250, attacks=['growl', 'kidnap_princess'])
st_character = st.sampled_from([samus, wario, bowser])
st_n_rounds = st.integer(min=0, max=10)
@st.composite
def fight_sequence(draw):
player_one = draw(st_character)
player_two = draw(st_character)
# don't test entire fights, just simulate one, record the steps,
# and check that the end state is what you expect
actions = [
dict(type='choose', player_number=1, player=player_one),
dict(type='choose', player_number=2, player=player_two)
]
# this filters out all test cases where players have the same character
assume(player_one != player_two)
n_rounds = draw(st_n_rounds)
both_alive = True
def _attack(player, other):
if not both_alive:
return
attack = draw(player.attacks)
response = draw(st.integers(min=0, max=len(attack)))
response_type = 'miss' if response == 0 else 'crit' if response == len(attack)) else 'hit'
actions.push(dict(type='attack', player=player, attack=attack, response=response_type))
if response_type == 'hit':
other.health -= len(attack)
elif response_type == 'crit':
other.health -= len(attack) * 2
if other.health <= 0:
actions.push(dict(type='ko', player=other))
for _ in range(n_rounds):
_attack(player_one, player_two)
_attack(player_two, player_one)
return actions
然后在您的测试用例中,将回放脚本提供给您的代码并检查结果是否一致。我希望你能以此为灵感。
添加回答
举报