Python unittest 单元测试框架
unittest
单元测试框架是受到 JUnit 的启发,与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化,配置共享和关机代码测试。支持将测试样例聚合到测试集中,并将测试与报告框架独立。
为了实现这些,unittest
通过面向对象的方式支持了一些重要的概念。
-
测试脚手架
-
test fixture 表示为了开展一项或多项测试所需要进行的准备工作,以及所有相关的清理操作。举个例子,这可能包含创建临时或代理的数据库、目录,再或者启动一个服务器进程。
-
测试用例
-
一个测试用例是一个独立的测试单元。它检查输入特定的数据时的响应。
unittest
提供一个基类:TestCase
,用于新建测试用例。 -
测试套件
-
test suite 是一系列的测试用例,或测试套件,或两者皆有。它用于归档需要一起执行的测试。
扫描二维码关注公众号,回复: 11355310 查看本文章 -
测试运行器(test runner)
-
test runner 是一个用于执行和输出测试结果的组件。这个运行器可能使用图形接口、文本接口,或返回一个特定的值表示运行测试的结果。
基本实例
下面例子是测试3个字符串的例子,分别为小写转大写、判断是否大写字符串,单词拆分。
断言
-
test_upper为定义断言是小写hello upper()后变为大写的HELLO,如果是相等的,说明函数upper()函数是正确的,否则是错误的。
-
test_isupper() 验证是判断是否是大写,断言HELLO.isupper()==true 断言是大写,正确的,hello.isupper的大写是错误的。2个断言,返回T。
-
test_split ()
-
import unittest class TestStringMethods(unittest.TestCase): def test_upper(self): self.assertEqual('hello'.upper(), 'HELLO') def test_isupper(self): self.assertTrue('HELLO'.isupper()) self.assertFalse('hello'.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) if __name__ == '__main__': unittest.main()
运行
可以用pytest tests.py
collected 3 items
testng.py ... [100%]
====== 3 passed in 0.04s ======
如果想看具体的可以加上-v
python testng.py -v
test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK
命令行界面
unittest 模块可以通过命令行运行模块、类和独立测试方法的测试:
python -m unittest test_module1 test_module2 python -m unittest test_module.TestClass python -m unittest test_module.TestClass.test_method
你可以传入模块名、类或方法名或他们的任意组合。
如:
python -m unittest testng.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
组织测试代码
单元测试的构建单位是 test cases :独立的、包含执行条件与正确性检查的方案。在 unittest
中,测试用例表示为 unittest.TestCase
的实例。通过编写 TestCase
的子类或使用 FunctionTestCase
编写你自己的测试用例。
一个 TestCase
实例的测试代码必须是完全自含的,因此它可以独立运行,或与其它任意组合任意数量的测试用例一起运行。
TestCase
的最简单的子类需要实现一个测试方法(例如一个命名以 test
开头的方法)以执行特定的测试代码:
import unittest class DefaultWidgetSizeTestCase(unittest.TestCase): def test_default_widget_size(self): widget = Widget('The widget') self.assertEqual(widget.size(), (50, 50))
可以看到,为了进行测试,我们使用了基类 TestCase
提供的其中一个 assert*()
方法。若测试不通过,将会引发一个带有说明信息的异常,并且 unittest
会将这个测试用例标记为测试不通过。任何其它类型的异常将会被当做错误处理。
可能同时存在多个前置操作相同的测试,我们可以把测试的前置操作从测试代码中拆解出来,并实现测试前置方法 setUp()
。在运行测试时,测试框架会自动地为每个单独测试调用前置方法。
import unittest class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget('The widget') def test_default_widget_size(self): self.assertEqual(self.widget.size(), (50,50), 'incorrect default size') def test_widget_resize(self): self.widget.resize(100,150) self.assertEqual(self.widget.size(), (100,150), 'wrong size after resize')
注解
多个测试运行的顺序由内置字符串排序方法对测试名进行排序的结果决定。
在测试运行时,若 setUp()
方法引发异常,测试框架会认为测试发生了错误,因此测试方法不会被运行。
相似的,我们提供了一个 tearDown()
方法在测试方法运行后进行清理工作。
import unittest class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget('The widget') def tearDown(self): self.widget.dispose()
若 setUp()
成功运行,无论测试方法是否成功,都会运行 tearDown()
。
这样的一个测试代码运行的环境被称为 test fixture 。一个新的 TestCase 实例作为一个测试脚手架,用于运行各个独立的测试方法。在运行每个测试时,setUp()
、tearDown()
和 __init__()
会被调用一次。
然而,如果你需要自定义你的测试套件的话,你可以参考以下方法组织你的测试:
def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase('test_default_widget_size')) suite.addTest(WidgetTestCase('test_widget_resize')) return suite if __name__ == '__main__': runner = unittest.TextTestRunner() runner.run(suite())