| 首页 > 深入Python > 单元测试 > 失败目的测试 | << >> | ||||
| diveintopython.org Python for experienced programmers | |||||
测试我们的函数在给出好的输入时是成功的,这是不够的。我们还必须测试在给出坏的输入时它们应失败。并且不只是简单地失败,它们必须按我们期望的方式失败。
回想我们对 toRoman 其它的需求:
在Python中,函数通过引发异常指出失败,同时 unittest 模块提供了函数,可以当给出坏的输入时测试函数是否引发一个特定异常。
class ToRomanBadInput(unittest.TestCase): def testTooLarge(self): """toRoman should fail with large input""" self.assertRaises(roman.OutOfRangeError, roman.toRoman, 4000)def testZero(self): """toRoman should fail with 0 input""" self.assertRaises(roman.OutOfRangeError, roman.toRoman, 0)
def testNegative(self): """toRoman should fail with negative input""" self.assertRaises(roman.OutOfRangeError, roman.toRoman, -1) def testDecimal(self): """toRoman should fail with non-integer input""" self.assertRaises(roman.NotIntegerError, roman.toRoman, 0.5)
|
unittest 的 TestCase 类提供了 assertRaises 方法,它接收下面的参数:我们正期待的异常、我们正在测试的函数和我们传给函数的参数。(如果我们正在测试的函数使用一个以上的参数,按顺序把它们全部传给 assertRaises,这个函数将把它们正确地传给我们正在测试的函数。)请仔细观察这里我们所做的:没有直接调用 toRoman 并且手工检查它引发的特殊异常(通过将它包括在try...except 块中),assertRaises 为我们都封装好了。我们只需要给出指定的异常(roman.OutOfRangeError),函数(toRoman),和 toRoman 的参数(4000) 即可,assertRaises 会小心地调用 toRoman 并且检查以确定它引发了 roman.OutOfRangeError。(最近我说过在Python中每个东西都是对象,包括函数和异常,是多么有用吗?) | |
|
与测试太大数一起,我们需要测试太小数。回想一下,罗马数字不能表示 0 或负数,所以我们对每种情况都有一个测试用例(testZero 和 testNegative)。在 testZero 中,我们在测试当使用 0 来调用 toRoman 时将引发 roman.OutOfRangeError 异常;如果它没有引发 roman.OutOfRangeError (或者是因为它返回一个实际值,或因为它引发了别的什么异常),这个测试被认为失败。 | |
|
需求 #3 指出:toRoman 不能接受非整数的小数,所以这里我们测试当使用一个小数(0.5)时,确定 toRoman 应引发 roman.NotIntegerError 异常。如果 toRoman 没有引发 roman.NotIntegerError ,这个测试被认为失败。 |
后面两个需求同前三个相似,除了它们用 fromRoman 代替了 toRoman:
需求 #4 按需求 #1的方式进行处理,对已知值的样本进行遍历,按顺序进行测试。需求#5按需求#2和#3的方式进行处理,通过对一系列坏的输入进行测试,确定 fromRoman 引发合适的异常。
class FromRomanBadInput(unittest.TestCase): def testTooManyRepeatedNumerals(self): """fromRoman should fail with too many repeated numerals""" for s in ('MMMM', 'DD', 'CCCC', 'LL', 'XXXX', 'VV', 'IIII'): self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)def testRepeatedPairs(self): """fromRoman should fail with repeated pairs of numerals""" for s in ('CMCM', 'CDCD', 'XCXC', 'XLXL', 'IXIX', 'IVIV'): self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s) def testMalformedAntecedent(self): """fromRoman should fail with malformed antecedents""" for s in ('IIMXCC', 'VX', 'DCM', 'CMM', 'IXIV', 'MCMC', 'XCX', 'IVI', 'LM', 'LD', 'LC'): self.assertRaises(roman.InvalidRomanNumeralError, roman.fromRoman, s)
成功目的测试 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 健壮目的测试 |