第16章 测试基础
1.先测试再编码
 为程序的各个部分编写测试很重要(单元测试)。
 “测试一点点,编写一点点”。
 1.准确的需求说明
 有爱阐述程序的目标,可编写需求说明。
 2.做好应对变化的准备
3.测试四步曲
 1.确定要实现的功能,记录下来,为之编写测试
 2.编写实现功能的框架代码,让程序能够运行,但测试仍无法通过,确保代码不正确时,测试能够报错。
 3.编写让测试能通过的代码,无需实现全部,只要能通过测试即可。
 4.改进(重构)代码以全面而准确地实现所需的功能,同时确保测试能通过。
2.测试工具
 有2个模块可帮助自动完成测试过程。
unittest:通用的测试框架
 doctest:为检查文档设计的,也可用来单元测试
 1.doctest
 实例:
 def square(x):
     '''
     计算平方并返回结果
     >>> square(2)
     4
     >>> square(3)
     9
     '''
     return x ** x
if __name__ == '__main__':
     import doctest, my_math
     doctest.testmod(my_math)
 保存为my_math.py
 然后在命令行运行 python my_math.py
 什么都不会输出。
 使用 python my_math.py -v 
 输出详细信息
2.unittest
 实例:
 #使用unittest测试 my_math
 import unittest, my_math
class ProductTestCase(unittest.TestCase):
    def test_integers(self):
         for x in range(-10, 10):
             for y in range(-10, 10):
                 p = my_math.product(x, y)
                 self.assertEqual(p, x * y, 'Integer multiplication failed')
    def test_float(self):
         for x in range(-10, 10):
             for y in range(-10, 10):
                 x = x / 10
                 y = y / 10
                 p = my_math.product(x, y)
                 self.assertEqual(p, x * y, 'Float multiplication failed')
if __name__ == '__main__': unittest.main()
#被测试的my_math 模块
 def product(x, y):
     #这句是故意出错来看看测试是不是有用
     if x == 7 and y == 9:
         return 'An insidious bug has surfaced!'
     return x * y 
3. 超越单元测试
 1.使用PyChecker和PyLint检查源代码
 PyChecker是检查python源代码的工具,
 PyLint支持PyChecker的大部分功能,还有其他功能,如变量名是否规范。。。
由于PyChecker有很多年没有更新了,所以就使用PyLint
 直接使用 pip install pylint 安装
使用PyLint 检查文件时,将模块(或包)名作为参数:
pylint module
实例:
 #使用模块subprocess调用外部检查器
 import unittest, my_math
 from subprocess import Popen, PIPE
class ProductTestCase(unittest.TestCase):
     #测试.
     def test_integers(self):
         for x in range(-10, 10):
             for y in range(-10, 10):
                 p = my_math.product(x, y)
                 self.assertEqual(p, x * y, 'Integer multiplication failed')
    def test_float(self):
         for x in range(-10, 10):
             for y in range(-10, 10):
                 x = x / 10
                 y = y / 10
                 p = my_math.product(x, y)
                 self.assertEqual(p, x * y, 'Float multiplication failed')
     
     def test_with_PyLint(self):
         cmd = 'pylint', '-rn', 'my_math'
         pylint = Popen(cmd,stdout=PIPE, stderr=PIPE)
         self.assertEqual(pylint.stdout.read(), '')
if __name__ == '__main__': unittest.main()
 #不知道为什么用不了这个方法,所以就直接在命令行用pylint module 了
 2.性能分析
 通常不需要过分追求速度。但是速度很慢时,就必须优化。性能分析帮助找到运行慢的地方。
 标准库模块profile(C语言版本cProfile)
 使用时只需调用其方法run并提供一个字符串参数。
 >>> import cProfile
 >>> from my_math import product
 >>> cProfile.run('product(1, 2)')
 将输出函数调用次数和花费时间
 如果向run提供第二个参数('my_math.profile')将分析结果保存到这个文件中,然后就可以使用模块psats分析结果









