Si vous avez entendu parler de "Test-Driven Development" (TDD: Test-Driven Development), les tests unitaires ne sont pas étrangers.
Les tests unitaires sont utilisés pour tester l'exactitude d'un module, d'une fonction ou d'une classe .
Par exemple, pour la fonction abs (), nous pouvons écrire les cas de test suivants:
- Entrez un nombre positif, tel que 1, 1,2, 0,99 et attendez-vous à ce que la valeur de retour soit la même que l'entrée;
- Entrez un nombre négatif, tel que -1, -1,2, -0,99, et attendez-vous à ce que la valeur de retour soit opposée à l'entrée;
- Entrez 0, attendez-vous à renvoyer 0;
- Entrez un type non numérique, tel que None, [], {}, en attendant qu'une TypeError soit renvoyée.
Mettre les cas de test ci-dessus dans un module de test est un test unitaire complet.
Si le test unitaire réussit, la fonction que nous avons testée peut fonctionner normalement. Si le test unitaire échoue, soit la fonction a un bogue, soit la condition de test est mal saisie. En bref, elle doit être corrigée pour que le test unitaire passe.
Quel est l'intérêt de réussir le test unitaire? Si nous modifions le code de la fonction abs () , il suffit de relancer le test unitaire. S'il réussit , cela signifie que notre modification n'affectera pas le comportement d'origine de la fonction abs () . Si le test échoue, il signifie notre modification. Contrairement au comportement d'origine, modifiez le code ou modifiez le test .
Le plus grand avantage de ce modèle de développement piloté par les tests est de garantir que le comportement d'un module de programme est conforme aux cas de test que nous avons conçus. Dans la future modification, cela peut grandement garantir que le comportement du module est toujours correct.
Écrivons une classe Dict. Le comportement de cette classe est le même que celui de dict, mais il est accessible via des attributs.
>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d.a
1
Le code de mydict.py est le suivant:
class Dict(dict):
def __init__(self, **kw)
super().__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
Afin d'écrire des tests unitaires, nous devons introduire le module unittest fourni avec Python et écrire mydict_test.py comme suit
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):
def test_init(self):
d = Dict(a=1, b='test')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, 'test')
self.assertTrue(isinstance(d, dict))
def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEqual(d.key, 'value')
def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEqual(d['key'], 'value')
def test_keyerror(self):
d = Dict()
with self.assertRaises(KeyError):
value = d['empty']
def test_attrerror(self):
d = Dict()
with self.assertRaises(AttributeError):
value = d.empty
Lors de l'écriture de tests unitaires, nous devons écrire une classe de test qui hérite de unittest.TestCase.
Les méthodes commençant par un test sont des méthodes de test. Les méthodes ne commençant pas par un test ne sont pas considérées comme des méthodes de test et ne seront pas exécutées pendant les tests.
Une méthode test_xxx () doit être écrite pour chaque type de test. Étant donné que unittest.TestCase fournit de nombreux jugements conditionnels intégrés, il suffit d'appeler ces méthodes pour affirmer si la sortie correspond à ce que nous attendons. L'assertion la plus couramment utilisée est assertEqual ():
self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等
Une autre assertion importante est de s'attendre à lancer un type d'erreur spécifié. Par exemple, lors de l'accès à une clé inexistante via d ['empty'], l'assertion lèvera une KeyError:
with self.assertRaises(KeyError):
value = d['empty']