You are here: Partenza > Dive Into Python > Test delle unità di codice > roman.py, fase 3 | << >> | ||||
Dive Into PythonPython per programmatori esperti |
Adesso che la funzione toRoman si comporta correttamente con input validi (numeri da 1 a 3999), è tempo di fare in modo che lo faccia anche con input non validi (qualsiasi altra cosa).
Se non lo avete ancora fatto, potete scaricare questo ed altri esempi usati in questo libro.
"""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, "decimals 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, "decimals can not be converted" NotIntegerError: decimals 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 passa ancora il test sui valori noti, il che è confortante. Tutti i test che erano stati superati nella fase 2 sono superati anche ora, indicando che le ultime modifiche non hanno scombinato niente. | |
Un fatto più eccitante è che tutti i nostri test di input non validi sono stati superati. Questo test, testDecimal, è passato con successo per via del controllo int(n) <> n. Quando un numero decimale è pasato a toRoman, il controllo int(n) <> n lo individua e solleva l'eccezione NotIntegerError, che è quello che si aspetta testDecimal. | |
Questo test, testNegative, è superato con successo per via del controllo not (0 < n < 4000), che solleva una eccezione OutOfRangeError, che è ciò che il test testNegative si aspetta. |
====================================================================== 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 cosa più importante che test delle unità di codice, condotti in modo esaustivo, possano comunicarci è il momento in cui si deve smettere di scrivere un programma. Quando tutti i test di un modulo hanno successo, è il momento di smettere di scrivere quel modulo. |
<< roman.py, fase 2 |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
roman.py, fase 4 >> |