13.4. 正面测试 (Testing for success)
Description: Python from novice to pro
Keywords: Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free

# 深入 Python :Dive Into Python 中文版 Python 从新手到专家 [Dip_5.4b_CPyUG_Release] | Find:

## 13.4. 正面测试 (Testing for success)

单元测试的基础是构建独立的测试用例 (test case)。一个测试用例只回答一个关于被测试代码的问题。

一个测试用例应该做到：

- 完全独立运行，不需要人工输入。单元测试应该是自动的。
- 可以自己判断被测试函数是通过还是失败，不需要人工干预结果。
- 独立运行，可以与其他测试用例隔离 (尽管它们可能测试着同一个函数)。每个测试用例是一个孤岛。

基于如上原则，让我们构建第一个测试用例。应符合如下要求：

1. `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)

| 编写测试用例的第一步就是继承 `unittest` 模块中的 `TestCase` 类，它提供了很多可以用在你的测试用例中来测试特定情况的有用方法。
| 这是我手工转换的一个 integer/numeral 对列表。它包含了最小的十个数、最大的数、每个单字符罗马数字对应的数，以及其他随机挑选的有效数样本。单元测试的关键不在于所有可能的输入，而是一个有代表性的样本。
| 每个独立测试本身都是一个方法，既不需要参数也不返回任何值。如果该方法正常退出没有引发异常，测试被认为通过；如果测试引发异常，测试被认为失败。
| 这里你真正调用了 `toRoman` 函数。(当然，函数还没有编写，但一旦被编写，这里便是调用之处。) 注意你在这里为 `toRoman` 函数定义了 API ：它必须接受整数 (待转换的数) 并返回一个字符串 (对应的罗马数字表示)，如果 API 不是这样，测试将失败。
| 同样值得注意，你在调用 `toRoman` 时没有试图捕捉任何可能发生的异常。这正是我们所希望的。以有效输入调用 `toRoman` 不会引发任何异常，而你看到的这些输入都是有效的。如果 `toRoman` 引发了异常，则测试失败。
| 假设 `toRoman` 函数被正确编写，正确调用，运行成功并返回一个值，最后一步便是检查这个返回值正确 与否。这是一个常见的问题，`TestCase` 类提供了一个方法：`assertEqual`，来测试两个值是否相等。如果 `toRoman` 返回的结果 (`value`) 不等于我们预期的值 (`numeral`)，`assertEqual` 将会引发一个异常，测试也就此失败。如果两个值相等，`assertEqual` 什么也不做。如果每个从 `toRoman` 返回的值都等于预期值，`assertEqual` 便不会引发异常，于是 `testToRomanKnownValues` 最终正常退出，这意味着 `toRoman` 通过了该测试。