Python模块学习之unittest


这篇笔记记录了Python内建模块unittest的知识点,所记录的内容均来自unittest的官方文档。

概述

unittest是Python标准库中的一个模块,使用它可以对Python代码进行单元测试,它支持如下特性:

  1. 测试自动化;
  2. 共享测试夹具(即测试用例的setUp()和tearDown()代码);
  3. 将测试用例组织成集合;
  4. 测试用例和测试报告框架之间相独立;

为了支持上述特性,unittest实现了如下几个重要的概念:

  • 测试夹具
    就是大家熟悉的setUp()和tearDown()机制。可以在Seup()中执行一些用例执行的准备工作,对应的在tearDown()中执行一些清理工作。
  • 测试用例
    这是单元测试最基本的内容,测试用例中构造输入参数,执行操作,然后检查结果是否符合预期。unittest中,每个测试用例都是一个TestCase对象。
  • 测试套件
    测试套件就是测试用例的集合,使用测试套件,可以自由的组合测试用例,以及控制它们的执行顺序。
  • 测试执行者
    负责执行测试用例,并且展示测试结果的组件。

测试用例

首先,一个个的测试用例函数要组织成类成员函数,这个类要继承自unittest.TestCase,举例如下:

import unittest

# 包含测试用例的类要继承自unittest.TestCase
class TestStringMethods(unittest.TestCase):
	# 1)测试用例函数必须要以test_开头,这样才会被框架认为是一条测试用例;
	# 2)测试用例函数只能含有一个self参数
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

if __name__ == '__main__':
	# unittest.main()会自动识别本模块中的测试用例并执行
    unittest.main()

测试夹具

有时候,我们需要在测试用例执行之前,执行一些准备工作,比如打开文件;在测试用例执行完毕后,执行一些清理工作,比如关闭文件,这时候测试夹具就派上了用场。

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()都会被执行,不管用例是否执行成功
	def tearDown(self):
        self.widget.dispose()

如上,setUp()和tearDown()实际上都是父类unittest.TestCase的方法,子类属于重写,每个类只有一个该方法,所以如果一个类中定义了多条测试用例,那么这些测试用例是共享setUp()和tearDown()的,这就是概述中所说的unittest是共享测试夹具的。

unittest还针对类和模块提供了夹具,即setUpClass()、tearDownClass()和setUpModule()、tearDownModule(),具体见Class and Module Fixtures

断言

测试用例编写过程中,其中最最关键的就是比较目标对象的运行结果和预期值,如果二者不一致,那么就是测试失败,在单元测试中,这种比较操作都是使用断言。unittest提供了丰富的断言,比如最基础的如下表所示,更具体的见手册。

MethodChecks thatNew in
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)bool(x) is True
assertFalse(x)bool(x) is False
assertIs(a, b)a is b3.1
assertIsNot(a, b)a is not b3.1
assertIsNone(x)x is None3.1
assertIsNotNone(x)x is not None3.1
assertIn(a, b)a in b3.1
assertNotIn(a, b)a not in b3.1
assertIsInstance(a, b)isinstance(a, b)3.2
assertNotIsInstance(a, b)not isinstance(a, b)3.2

测试套件

测试套件就是测试用例的集合,unittest.TestSuite类实现了测试套件,使用测试套件,我们可以自由的组织测试用例。

添加测试用例

既然是容器,那么最重要的操作就是向容器中添加测试用例了,可以在构造的时候就指定,也可以通过addTest()方法。

# test可以是unittest.TestCase对象,或者unittest.TestSuite对象
class unittest.TestSuite(tests=()) 
# test可以是unittest.TestCase对象,或者unittest.TestSuite对象
addTest(test)
# tests可以是一个可迭代的unittest.TestCase对象集合,或者unittest.TestSuite对象
addTests(tests)

可以看出,unittest.TestSuite是可以嵌套的,此外unittest.TestSuite也实现了_iter_()魔法方法,所以它本身是一个可迭代对象,对它迭代会依次得到其中的测试用例。

测试用例加载器

如上,我们可以手动实例化unittest.TestSuite对象,然后调用其addTest()等方法向其中添加测试用例。但是unittest提供了更加便捷的unittest.TestLoader类来帮助我们从类和模块中创建unittest.TestSuite对象。

常见的一些方法如下:

# 加载一个测试类中的所有测试用例
loadTestsFromTestCase(testCaseClass) 
# 加载一个模块中的所有测试用例
loadTestsFromModule(module, pattern=None) 

测试执行者

测试用例组织成unittest.TestSuite后,需要执行者将其运行起来,unittest提供了文本格式的执行者unittest.TextTestRunner(其执行结果是文本格式的),它最重要的一个方法就是run()。

# test是一个unittest.TestCase对象或者unittest.TestSuite对象,返回unittest.TestResult对象来表示这些用例的执行结果
run(test)

用例执行结果

unittest.TestResult类记录了用例集的执行结果,对于想生成自定义测试报告的情景,可以从测试执行者中获取到该对象,具体见手册中的class unittest.TestResult

其它主题

  1. unittest支持从命令行执行测试用例,具体见手册的“Command-Line Interface”
  2. 老测试用例整改。在老测试用例的基础上做少量修改后就可以复用unittest,具体见Re-using old test code
  3. 如果想要跳过部分用例,或者期望用例的执行结果是失败的,那么可以使用unittest的skip修饰符,具体见Skipping tests and expected failures。个人理解该功能意义不大,为何不直接调整测试用例的逻辑,反而做这种修改;
  4. 如果一组用例逻辑非常相似,那么考虑使用subTest()来优化它们,这样可以避免冗余代码,具体见Distinguishing test iterations using subtests

总结

对于unittest模块的使用,如果我们不想对用例的执行过程以及执行结果进行任何的定制,那么只需从unittest.TestCase派生一个子类,在其中实现用例方法,然后用unittest.main()函数触发所有用例的执行即可。

如果我们想要对用例的执行进行定制,那么就需要如下几步:

  1. 编写用例(从unittest.TestCase类派生子类);
  2. 组织测试用例(实例化unittest.TestSuite对象,可能会用到unittest.TestLoader);
  3. 执行用例(实例化unittest.TextTestRunner,或者unittest.main()方法);
  4. 获取用例执行结果(unittest.TestResult类,此时步骤三必须使用用例执行者)。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值