1. 文档测试
    2. 阅读: 80195
    3. 如果你经常阅读Python的官方文档,可以看到很多文档都有示例代码。比如re模块就带了很多示例代码:
    4. >>> import re
    5. >>> m = re.search('(?<=abc)def', 'abcdef')
    6. >>> m.group(0)
    7. 'def'
    8. 可以把这些示例代码在Python的交互式环境下输入并执行,结果与文档中的示例代码显示的一致。
    9. 这些代码与其他说明可以写在注释中,然后,由一些工具来自动生成文档。既然这些代码本身就可以粘贴出来直接运行,那么,可不可以自动执行写在注释中的这些代码呢?
    10. 答案是肯定的。
    11. 当我们编写注释时,如果写上这样的注释:
    12. def abs(n):
    13. '''
    14. Function to get absolute value of number.
    15. Example:
    16. >>> abs(1)
    17. 1
    18. >>> abs(-1)
    19. 1
    20. >>> abs(0)
    21. 0
    22. '''
    23. return n if n >= 0 else (-n)
    24. 无疑更明确地告诉函数的调用者该函数的期望输入和输出。
    25. 并且,Python内置的"文档测试"doctest)模块可以直接提取注释中的代码并执行测试。
    26. doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。只有测试异常的时候,可以用...表示中间一大段烦人的输出。
    27. 让我们用doctest来测试上次编写的Dict类:
    28. # mydict2.py
    29. class Dict(dict):
    30. '''
    31. Simple dict but also support access as x.y style.
    32. >>> d1 = Dict()
    33. >>> d1['x'] = 100
    34. >>> d1.x
    35. 100
    36. >>> d1.y = 200
    37. >>> d1['y']
    38. 200
    39. >>> d2 = Dict(a=1, b=2, c='3')
    40. >>> d2.c
    41. '3'
    42. >>> d2['empty']
    43. Traceback (most recent call last):
    44. ...
    45. KeyError: 'empty'
    46. >>> d2.empty
    47. Traceback (most recent call last):
    48. ...
    49. AttributeError: 'Dict' object has no attribute 'empty'
    50. '''
    51. def __init__(self, **kw):
    52. super(Dict, self).__init__(**kw)
    53. def __getattr__(self, key):
    54. try:
    55. return self[key]
    56. except KeyError:
    57. raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
    58. def __setattr__(self, key, value):
    59. self[key] = value
    60. if __name__=='__main__':
    61. import doctest
    62. doctest.testmod()
    63. 运行python mydict2.py
    64. $ python mydict2.py
    65. 什么输出也没有。这说明我们编写的doctest运行都是正确的。如果程序有问题,比如把__getattr__()方法注释掉,再运行就会报错:
    66. $ python mydict2.py
    67. **********************************************************************
    68. File "/Users/michael/Github/learn-python3/samples/debug/mydict2.py", line 10, in __main__.Dict
    69. Failed example:
    70. d1.x
    71. Exception raised:
    72. Traceback (most recent call last):
    73. ...
    74. AttributeError: 'Dict' object has no attribute 'x'
    75. **********************************************************************
    76. File "/Users/michael/Github/learn-python3/samples/debug/mydict2.py", line 16, in __main__.Dict
    77. Failed example:
    78. d2.c
    79. Exception raised:
    80. Traceback (most recent call last):
    81. ...
    82. AttributeError: 'Dict' object has no attribute 'c'
    83. **********************************************************************
    84. 1 items had failures:
    85. 2 of 9 in __main__.Dict
    86. ***Test Failed*** 2 failures.
    87. 注意到最后3行代码。当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest。所以,不必担心doctest会在非测试环境下执行。
    88. 练习
    89. 对函数fact(n)编写doctest并执行:
    90. # -*- coding: utf-8 -*-
    91. def fact(n):
    92. '''
    93. Calculate 1*2*...*n
    94. >>> fact(1)
    95. 1
    96. >>> fact(10)
    97. ?
    98. >>> fact(-1)
    99. ?
    100. '''
    101. if n < 1:
    102. raise ValueError()
    103. if n == 1:
    104. return 1
    105. return n * fact(n - 1)
    106. if __name__ == '__main__':
    107. import doctest
    108. doctest.testmod()
    109. Run
    110. 小结
    111. doctest非常有用,不但可以用来测试,还可以直接作为示例代码。通过某些文档生成工具,就可以自动把包含doctest的注释提取出来。用户看文档的时候,同时也看到了doctest
    112. 参考源码
    113. mydict2.py