一、单元测试
1、单元测试:在计算机编程中,单元测试(Unit Testing),又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
2、例子:比如我们现在有一个加法函数,需要我们输入两个值,那么怎么保证我们写的函数是没有问题的呢?那我们要调用这个加法函数,然后传入两个值,查看返回值是否正确。这就是在做单元测试。
二、unittest单元测试框架
1、官方中文网址:https://docs.python.org/zh-cn/3.7/library/unittest.html
2、相关介绍:unittest单元测试框架是受到 JUnit 的启发,与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化,配置共享和关机代码测试。支持将测试样例聚合到测试集中,并将测试与报告框架独立。
3、为了实现这些,unittest通过面向对象的方式支持了一些重要的概念。
3.1、测试脚手架
test fixture表示为了开展一项或多项测试所需要进行的准备工作,以及所有相关的清理操作。举个例子,这可能包含创建临时或代理的数据库、目录,再或者启动一个服务器进程。又或者是,我们执行一条创建文章的测试用例,但是如果我们调用创建文章的接口,需要我们进行登录,我们可以把登录作为一个test fixture。
3.2、测试用例
一个测试用例是一个独立的测试单元,它检查输入特定的数据时的响应。unittest提供一个基类:TestCase,用于新建测试用例。
3.3、测试套件
test suite是一系列的测试用例,或测试套件,或两者皆有。它用于归档需要一起执行的测试。
3.4、测试运行器(test runner)
test runner是一个用于执行和输出测试结果的组件。这个运行器可能使用图形接口、文本接口,或返回一个特定的值表示运行测试的结果。
4、官网演示代码:测试三种字符串方法
import unittest
#继承 unittest.TestCase
class TestStringMethods(unittest.TestCase):
#三个独立的测试是三个类的方法,这些方法的命名都以 test 开头。 这个命名约定告诉测试运行者类的哪些方法表示测试。
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
#每个测试的关键是:调用 assertEqual() 来检查预期的输出; 调用 assertTrue() 或 assertFalse() 来验证一个条件;调用 assertRaises() 来验证抛出了一个特定的异常。
#使用这些方法而不是 assert 语句是为了让测试运行者能聚合所有的测试结果并产生结果报告。
if __name__ == '__main__':
unittest.main()
#unittest.main() 提供了一个测试脚本的命令行接口。
运行结果:
在调用测试脚本时添加-v参数使unittest.main()显示更为详细的信息:
5、命令行界面:
unittest 模块可以通过命令行运行模块、类和独立测试方法的测试,你可以传入模块名、类或方法名或他们的任意组合。而且,测试模块可以通过文件路径指定。
python -m unittest test_module1 test_module2#模块
python -m unittest test_module.TestClass#类
python -m unittest test_module.TestClass.test_method#方法
5.1、传入测试模块:
5.2、传入类:
5.3、传入方法:
5.4、传入组合,比如方法的组合:
5.5、传入文件路径:路径通过去除 '.py' 、把分隔符转换为 '.' 转换为模块名。
6、命令行选项:
6.1、-b, --buffer
在测试运行时,标准输出流与标准错误流会被放入缓冲区。成功的测试的运行时输出会被丢弃;测试不通过时,测试运行中的输出会正常显示,错误会被加入到测试失败信息。
6.2、-c, --catch
当测试正在运行时,Control-C会等待当前测试完成,并在完成后报告已执行的测试的结果。当再次按下Control-C时,引发平常的KeyboardInterrupt异常。
6.3、-f, --failfast
当出现第一个错误或者失败时,停止运行测试。
6.4、-k
只运行匹配模式或子串的测试方法和类。可以多次使用这个选项,以便包含匹配子串的所有测试用例。该匹配是大小写敏感的。例如,-kfoo可以匹配到foo_tests.SomeTest.test_something和bar_tests.SomeTest.test_foo,但是不能匹配到bar_tests.FooTest.test_something。
6.5、--locals
在回溯中显示局部变量。
6.6、命令行亦可用于探索性测试,以运行一个项目的所有测试或其子集。
7、探索性测试:Unittest支持简单的测试搜索。
7.1、探索性测试在TestLoader.discover()中实现,但也可以通过命令行使用。它在命令行中的基本用法如下:
cd project_directory
python -m unittest discover
#python -m unittest 与 python -m unittest discover 等价。如果你需要向探索性测试传入参数,必须显式地使用 discover 子命令。
7.2、discover有以下选项:
-v, --verbose
更详细地输出结果。
-s, --start-directory directory
开始进行搜索的目录(默认值为当前目录.)。
-p, --pattern pattern
用于匹配测试文件的模式(默认为test*.py)。
-t, --top-level-directory directory
指定项目的最上层目录(通常为开始时所在目录)。
7.3、比如,以gw_unit.py为例,我们执行探索性测试,是没有结果的:
而如果我们把命名改为test_gw_unit.py,再执行探索性测试,就可以成功执行到用例,因为用于匹配测试文件的模式默认是test*.py: