You are here: Sommaire > Plongez au coeur de Python > Ecriture des tests en premier > roman.py, étape 3 | << >> | ||||
Plongez au coeur de PythonDe débutant à expert |
Maintenant que toRoman se comporte correctement avec des entrées correctes (des entiers de 1 à 3999), il est temps de faire en sorte qu’il se comporte bien avec des entrées incorrectes (tout le reste).
Ce fichier est disponible dans le sous-répertoire py/roman/stage3/ du répertoire des exemples.
Si vous ne l’avez pas déjà fait, vous pouvez télécharger cet exemple ainsi que les autres exemples du livre.
"""Convert to and from Roman numerals""" #Define exceptions class RomanError(Exception): pass class OutOfRangeError(RomanError): pass class NotIntegerError(RomanError): pass class InvalidRomanNumeralError(RomanError): pass #Define digit mapping romanNumeralMap = (('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), ('IV', 4), ('I', 1)) def toRoman(n): """convert integer to Roman numeral""" if not (0 < n < 4000): raise OutOfRangeError, "number out of range (must be 1..3999)" if int(n) <> n: raise NotIntegerError, "non-integers can not be converted" result = "" for numeral, integer in romanNumeralMap: while n >= integer: result += numeral n -= integer return result def fromRoman(s): """convert Roman numeral to integer""" pass
>>> import roman3 >>> roman3.toRoman(4000) Traceback (most recent call last): File "<interactive input>", line 1, in ? File "roman3.py", line 27, in toRoman raise OutOfRangeError, "number out of range (must be 1..3999)" OutOfRangeError: number out of range (must be 1..3999) >>> roman3.toRoman(1.5) Traceback (most recent call last): File "<interactive input>", line 1, in ? File "roman3.py", line 29, in toRoman raise NotIntegerError, "non-integers can not be converted" NotIntegerError: non-integers can not be converted
fromRoman should only accept uppercase input ... FAIL toRoman should always return uppercase ... ok fromRoman should fail with malformed antecedents ... FAIL fromRoman should fail with repeated pairs of numerals ... FAIL fromRoman should fail with too many repeated numerals ... FAIL fromRoman should give known result with known input ... FAIL toRoman should give known result with known input ... ok fromRoman(toRoman(n))==n for all n ... FAIL toRoman should fail with non-integer input ... ok toRoman should fail with negative input ... ok toRoman should fail with large input ... ok toRoman should fail with 0 input ... ok
toRoman passe toujours le test des valeurs connues, ce qui est réconfortant. Tous les tests qui passaient à l’étape 2 passent toujours, donc notre nouveau code n’a rien endommagé. | |
Plus enthousiasmant, maintenant notre test de valeurs incorrectes passe. Ce test, testDecimal, passe grâce à la vérification int(n) <> n. Lorsqu’un nombre décimal est passé à toRoman, int(n) <> n le voit et déclenche l’exception NotIntegerError, qui est ce que testDecimalattend. | |
Ce test, testNegative, passe grâce à la vérification not (0 < n < 4000), qui déclenche une exception OutOfRangeError, qui est ce que testNegative attend. |
====================================================================== FAIL: fromRoman should only accept uppercase input ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 156, in testFromRomanCase roman3.fromRoman, numeral.lower()) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should fail with malformed antecedents ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 133, in testMalformedAntecedent self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should fail with repeated pairs of numerals ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 127, in testRepeatedPairs self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should fail with too many repeated numerals ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 122, in testTooManyRepeatedNumerals self.assertRaises(roman3.InvalidRomanNumeralError, roman3.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ====================================================================== FAIL: fromRoman should give known result with known input ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 99, in testFromRomanKnownValues self.assertEqual(integer, result) File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual raise self.failureException, (msg or '%s != %s' % (first, second)) AssertionError: 1 != None ====================================================================== FAIL: fromRoman(toRoman(n))==n for all n ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage3\romantest3.py", line 141, in testSanity self.assertEqual(integer, result) File "c:\python21\lib\unittest.py", line 273, in failUnlessEqual raise self.failureException, (msg or '%s != %s' % (first, second)) AssertionError: 1 != None ---------------------------------------------------------------------- Ran 12 tests in 0.401s FAILED (failures=6)
La chose la plus importante que des tests unitaires complets vous disent est quand vous arrêter d’écrire du code. Quand tous les tests unitaires d’une fonction passent, arrêtez d’écrire le code de la fonction. Quand tous les tests d’un module passent, arrêtez d’écrire le code du module. |
<< roman.py, étape 2 |
| 1 | 2 | 3 | 4 | 5 | |
roman.py, étape 4 >> |