13.4. 正面测试 (Testing for success)
单元测试的基础是构建独立的测试用例 (test case)。一个测试用例只回答一个关于被测试代码的问题。
一个测试用例应该做到:
- 完全独立运行,不需要人工输入。单元测试应该是自动的。
- 可以自己判断被测试函数是通过还是失败,不需要人工干预结果。
- 独立运行,可以与其他测试用例隔离 (尽管它们可能测试着同一个函数)。每个测试用例是一个孤岛。
基于如上原则,让我们构建第一个测试用例。应符合如下要求:
toRoman
应该为所有1
到3999
的整数返回罗马数字表示。
例 13.2. testToRomanKnownValues
class KnownValues(unittest.TestCase):
knownValues = ( (1, 'I'),
(2, 'II'),
(3, 'III'),
(4, 'IV'),
(5, 'V'),
(6, 'VI'),
(7, 'VII'),
(8, 'VIII'),
(9, 'IX'),
(10, 'X'),
(50, 'L'),
(100, 'C'),
(500, 'D'),
(1000, 'M'),
(31, 'XXXI'),
(148, 'CXLVIII'),
(294, 'CCXCIV'),
(312, 'CCCXII'),
(421, 'CDXXI'),
(528, 'DXXVIII'),
(621, 'DCXXI'),
(782, 'DCCLXXXII'),
(870, 'DCCCLXX'),
(941, 'CMXLI'),
(1043, 'MXLIII'),
(1110, 'MCX'),
(1226, 'MCCXXVI'),
(1301, 'MCCCI'),
(1485, 'MCDLXXXV'),
(1509, 'MDIX'),
(1607, 'MDCVII'),
(1754, 'MDCCLIV'),
(1832, 'MDCCCXXXII'),
(1993, 'MCMXCIII'),
(2074, 'MMLXXIV'),
(2152, 'MMCLII'),
(2212, 'MMCCXII'),
(2343, 'MMCCCXLIII'),
(2499, 'MMCDXCIX'),
(2574, 'MMDLXXIV'),
(2646, 'MMDCXLVI'),
(2723, 'MMDCCXXIII'),
(2892, 'MMDCCCXCII'),
(2975, 'MMCMLXXV'),
(3051, 'MMMLI'),
(3185, 'MMMCLXXXV'),
(3250, 'MMMCCL'),
(3313, 'MMMCCCXIII'),
(3408, 'MMMCDVIII'),
(3501, 'MMMDI'),
(3610, 'MMMDCX'),
(3743, 'MMMDCCXLIII'),
(3844, 'MMMDCCCXLIV'),
(3888, 'MMMDCCCLXXXVIII'),
(3940, 'MMMCMXL'),
(3999, 'MMMCMXCIX'))
def testToRomanKnownValues(self):
"""toRoman should give known result with known input"""
for integer, numeral in self.knownValues:
result = roman.toRoman(integer)
self.assertEqual(numeral, result)
[1] | 编写测试用例的第一步就是继承 unittest 模块中的 TestCase 类,它提供了很多可以用在你的测试用例中来测试特定情况的有用方法。 |
[2] | 这是我手工转换的一个 integer/numeral 对列表。它包含了最小的十个数、最大的数、每个单字符罗马数字对应的数,以及其他随机挑选的有效数样本。单元测试的关键不在于所有可能的输入,而是一个有代表性的样本。 |
[3] | 每个独立测试本身都是一个方法,既不需要参数也不返回任何值。如果该方法正常退出没有引发异常,测试被认为通过;如果测试引发异常,测试被认为失败。 |
[4] | 这里你真正调用了 toRoman 函数。(当然,函数还没有编写,但一旦被编写,这里便是调用之处。) 注意你在这里为 toRoman 函数定义了 API :它必须接受整数 (待转换的数) 并返回一个字符串 (对应的罗马数字表示),如果 API 不是这样,测试将失败。 |
[5] | 同样值得注意,你在调用 toRoman 时没有试图捕捉任何可能发生的异常。这正是我们所希望的。以有效输入调用 toRoman 不会引发任何异常,而你看到的这些输入都是有效的。如果 toRoman 引发了异常,则测试失败。 |
[6] | 假设 toRoman 函数被正确编写,正确调用,运行成功并返回一个值,最后一步便是检查这个返回值正确 与否。这是一个常见的问题,TestCase 类提供了一个方法:assertEqual ,来测试两个值是否相等。如果 toRoman 返回的结果 (value ) 不等于我们预期的值 (numeral ),assertEqual 将会引发一个异常,测试也就此失败。如果两个值相等,assertEqual 什么也不做。如果每个从 toRoman 返回的值都等于预期值,assertEqual 便不会引发异常,于是 testToRomanKnownValues 最终正常退出,这意味着 toRoman 通过了该测试。 |