测试分为黑盒测试和白盒测试。
最简单的测试方法:即时测试。也就是编写一点代码,就测试一点。
1. 测试的一些基础知识 2. 测试工具(doctest、unittest) 3. 检查代码(PyLint、Flake8) 4. 性能分析
1.先测试,后编码
coding -> run -> testing -> find bug -> 修复
1.1 为代码规定一个边界
为代码划定边界的方法就是测试驱动开发,也就是在编写代码之前,先为代码编写测试程序,然后基于这些测试程序编写代码。当代码编写完成,就可以运行这些测试程序自动检测程序中的bug。
1.2 测试的步骤
确定代码要达到的预期,然后为这个预期编写测试代码。
编写骨架代码。
编写业务逻辑代码。
修改或重构代码
import math # 计算圆的面积 def circleArea(r): # 相当于骨架代码 return math.pi * r * r # 相当于业务逻辑代码 r = 100 # 第1个边界,圆半径必须大于0 if r <= 0: print('测试失败,圆半径必须大于0') else: area = circleArea(r) # 第2个边界,圆面积不能大于1000 if area > 1000: print('测试失败,圆面积不能大于1000') else: print('测试成功.')
结果:
测试失败,圆面积不能大于1000
2.测试工具
Python标准库中有两个测试框架可供使用:
1.doctest:用于检查文档,也可以用来编写单元测试,而且比较容易学习。
2.unittest:通用测试框架。
2.1 doctest
doctest模块是用来检查文档的,但也可以用来编写测试代码。只是这些测试代码要写在多行注释里。
1.要测试的代码前面需要加三个大于号(>),
2.然后返回值放到下一行。
3.最后,通过doctest模块中的testmod函数测试指定的模块,测试结果会通过Console输出。
''' 测试square函数 >>> square(2) 4 >>> square(6) 36 测试add函数 >>> add(2,2) 4 >>> add(4,5) 9 ''' def square(x): return x * x def add(x,y): return x + y import doctest,demo02 # 导入doctest模块以及当前模块(demo02) doctest.testmod(demo02) # 测试demo02模块中的代码 ''' testmod函数测试模块还需要注意以下几点: 1. testmod函数只会处理模块中的第1个多行注释,并且不能在第1个多行注释前面 有任何Python代码 2. >>>与要指定的代码之间要有空格,不能连在一起 3. 函数返回值后面不要有空格,否则无法通过测试 4. 用于注释的文本和函数返回值之间要有空行,否则系统会将注释当做函数返回值处理。 '''
2.2 unittest
unittest比doctest在使用上复杂一些,但更灵活。unittest的使用方法有些类似于Java测试框架JUnit。
官方文档:https://docs.python.org/3/library/unittest.html。
使用unittest编写测试代码的步骤如下:
导入unittest模块
编写测试类,测试类必须从unittest.TestCase或其子类继承
编写测试用例
调用unittest模块中的main函数开始测试
import unittest,demo02 # 导入unittest模块以及当前模块(demo02) # 定义测试类 class MyTest(unittest.TestCase): # 用于测试square函数的方法 def testSquare(self): # 使用一段连续的整数测试square函数 for x in range(-20,20): # 将每一个x 传入square函数,并获取返回结果 result = demo02.square(x) # 调用assertEqual方法进行测试,如果该方法的第1个参数值和第2个参数值不相等 # 就会抛出异常,异常信息就是第3个参数的值。 self.assertEqual(result, x * x, '%d的二次方失败' % x) # 用于测试add函数的方法 def testAdd(self): # 使用2个连续的整数序列测试add函数 for x in range(-20,20): for y in range(-10,10): # 将 x,y传入add函数,并获取返回值。 result = demo02.add(x,y) # 调用assertEqual方法进行测试 self.assertEqual(result, x + y,'%d + %d失败' % (x,y)) unittest.main() # 调用main函数开始测试
3.检查源代码
对代码风格,错误、警告等内容进行检测。工具:PyLint Flake8等
3.1 PyLint
Pylint用来检测Python代码是否符合规范。注:不规范的代码不是错误代码,而是不符合一般的编码习惯。
pip install pylint
''' 模块文档 ''' for i in range(1, 10): print(i)
PyLint中有一个命令行工具pylint,可以在终端执行如下的命令检查上面的代码是否符合规范,假设这段代码保存在test.py文件中。
命令行代码:pylint test.py
3.2 Flake8
基本功能:检测Python代码的错误和警告。
官方文档:http://flake8.pycqa.org/en/latest/user/index.html
安装:pip install flake8
# test1.py import sys import os for i in range(1, 10): print(ia) fun(i) # 注:变量ia 和函数fun都没有定义,导入的sys模块和os模块都没有使用。
命令行终端中:flake8 test1.py
对于一个非常大的脚本文件,可能输出的异常信息很多,因此,也可以通过Flake8的命令行参数只检测某些特定的异常或忽略一些不感兴趣的异常。
只检测某些特定的异常 flake8 --select F401 test1.py
果想选择更多的异常标识,需要在多个异常标识之间用逗号(,)分隔 flake8 --select F401,F821 test1.py
如果想忽略某某些标识,可以使用--ignore命令行参数 flake8 --ignore F401 test1.py
Flake8还支持API方法,也就是可以直接在程序中对Python脚本文件进行检测。
from flake8.api import legacy as flake8 styleGuide = flake8.get_style_guide(ignore=['F401']) styleGuide.check_files(['test1.py'])
4.性能分析
性能是程序测试的一项重要指标,如果程序的bug大多已经排除,但是程序的性能堪忧,轻者会降低用户体验,重者会造成系统资源大量消耗,甚至会导致系统崩溃。
Python内部已经内建了一些性能模块,如:profile模块。通过profile模块中相应的API,可以得到Python程序中函数的调用次数、执行时间以及其他信息。
import pstats # 使用pstats模块的Stats类读取test.profile文件,并输出该文件的内容。 p = pstats.Stats('test.profile') p.print_stats()