You are here: Sommaire > Plongez au coeur de Python > Ecriture des tests en premier > roman.py, étape 4 | << >> | ||||
Plongez au coeur de PythonDe débutant à expert |
Maintenant que toRoman est terminé, nous devons passer à fromRoman. Grâce à notre structure de données élaborée qui fait correspondre les nombres romains à des valeurs entières, ce n’est pas plus difficile que pour toRoman.
Ce fichier est disponible dans le sous-répertoire py/roman/stage4/ 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)) # toRoman function omitted for clarity (it hasn't changed) def fromRoman(s): """convert Roman numeral to integer""" result = 0 index = 0 for numeral, integer in romanNumeralMap: while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) return result
Le principe est le même que pour toRoman. Nous parcourons notre structure de données de chiffres romains (un tuple de tuples) et au lieu de chercher la plus grande valeur possible, nous cherchons la chaîne représentant les chiffres romains les plus «haut» possible. |
Si vous n’êtes pas sûr de comprendre comment fonctionne fromRoman, ajoutez une instruction print à la fin de la boucle while :
while s[index:index+len(numeral)] == numeral: result += integer index += len(numeral) print 'found', numeral, 'of length', len(numeral), ', adding', integer
>>> import roman4 >>> roman4.fromRoman('MCMLXXII') found M , of length 1, adding 1000 found CM , of length 2, adding 900 found L , of length 1, adding 50 found X , of length 1, adding 10 found X , of length 1, adding 10 found I , of length 1, adding 1 found I , of length 1, adding 1 1972
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 ... ok toRoman should give known result with known input ... ok fromRoman(toRoman(n))==n for all n ... ok 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
Il y a deux bonnes nouvelles. La première est que fromRoman marche pour des entrées correctes, au moins pour toutes les valeurs connues que nous testons. | |
La deuxième est que notre test de cohérence passe également. Ces deux résultats nous permettent d’être raisonnablement sûrs que toRoman comme fromRoman marchent correctement pour toutes les valeurs correctes. (Cela n’est pas garanti, il est théoriquement possible que toRoman ait un bogue qui produise des chiffres romains erronés pour certaines entrées, et que fromRoman ait un bogue correspondant produisant les mêmes valeurs entières erronées pour les mêmes chiffres romains. En fonction de votre application et de vos besoins, cette possibilité peut vous déranger ; dans ce cas écrivez des tests plus exhaustifs jusqu’à ce que vous ayez l’esprit tranquille.) |
====================================================================== FAIL: fromRoman should only accept uppercase input ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\docbook\dip\py\roman\stage4\romantest4.py", line 156, in testFromRomanCase roman4.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\stage4\romantest4.py", line 133, in testMalformedAntecedent self.assertRaises(roman4.InvalidRomanNumeralError, roman4.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\stage4\romantest4.py", line 127, in testRepeatedPairs self.assertRaises(roman4.InvalidRomanNumeralError, roman4.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\stage4\romantest4.py", line 122, in testTooManyRepeatedNumerals self.assertRaises(roman4.InvalidRomanNumeralError, roman4.fromRoman, s) File "c:\python21\lib\unittest.py", line 266, in failUnlessRaises raise self.failureException, excName AssertionError: InvalidRomanNumeralError ---------------------------------------------------------------------- Ran 12 tests in 1.222s FAILED (failures=4)
<< roman.py, étape 3 |
| 1 | 2 | 3 | 4 | 5 | |
roman.py, étape 5 >> |