2012-06-11 1 views
5

Il existe certains domaines d'application (par exemple GameDev) dans lesquels de nombreuses fonctions doivent être créées en utilisant des valeurs aléatoires pour produire leur sortie. Un des exemples est présenté ci-dessous:Comment valider l'exactitude des fonctions qui utilisent le hasard?

def generate_key(monster_key_drop_coef): 
    key_letters = string.ascii_uppercase 
    rand = random.random() 
    if monster_key_drop_coef < rand: 
     return None 

    button = {} 
    button["type"] = random.choice([1,2,3]) 
    button["letter"] = random.choice(key_letters) 
    return button 

Cette fonction génère la chute de l'élément en fonction de plusieurs opérations aléatoires. Le problème apparaît si vous voulez valider automatiquement l'exactitude de cette fonction. Les valeurs générées ne sont pas déterministes et l'écriture des tests de régression semble impossible.

Mes questions sont les suivantes:

  1. Est-ce possible d'écrire des tests de régression utiles pour ce type de fonctions?
  2. Existe-t-il une approche générale pour créer d'autres types de tests dans ce cas?
+4

Il y a des livres entiers écrits sur ce sujet. Exemple: http://www.johndcook.com/Beautiful_Testing_ch10.pdf –

+1

Le fait de se moquer du RNG pour fournir des résultats connus (puis de tester des résultats spécifiques pour lesquels le résultat souhaité est connu) est une approche. –

Répondre

3

L'un des tests unitaires utiles est présenté ci-dessous:

def test_generate_key(): 
    button_list = [] 
    for _ in range(1, 1000): 
     button_list.append(generate_key(0.2)) 

    is_all_none = True 
    is_not_none = False 
    for key in button_list: 
     is_all_none &= (key is None) 
     is_not_none |= (key is not None) 

    assert is_all_none == False 
    assert is_not_none == True 

Il valide la signature de fonction, couvre toutes les lignes de code de fonction (bonne probabilité) et passera dans 99,999% des cas. Aussi validé cette fonction produit une baisse d'au moins un de 1000 et parfois ne génère pas de baisse. 0.2 est la probabilité de chute d'un objet.

2

Je voudrais réécrire la fonction pour utiliser l'injection de dépendance (le générateur de nombres aléatoires est transmis en tant que paramètre à la fonction). Ensuite, vous pouvez passer un simulacre d'un générateur de nombres aléatoires pour tester votre fonction avec différentes entrées "aléatoires" déterministes.

Bien sûr, vous pouvez également tester vos assertions qui ne dépendent pas des résultats de l'appel au hasard. Tels que:

  • Les fonctions renvoie None ou un dict avec les clés "type" et "lettre".
  • Si un dictionnaire est renvoyé, les valeurs sont du type et de la plage appropriés.

Je ne voudrais jamais écrire un unittest qui a des résultats non déterministes, même 1 sur mille. Je m'inquiète de chaque échec du test, et les résultats stochastiques seraient dérangeants. Vous feriez mieux d'encapsuler votre caractère aléatoire, de sorte que la fonction puisse être testée indépendamment du générateur de nombres aléatoires.

Questions connexes