初步认识

TestCase是单元测试中最常用的类,例如,接下来测试下面这个小函数

add = lambda a,b : a+b
div = lambda a,b : a/b

其测试方法为

import unittest
class TestTest(unittest.TestCase):
    def test_div(self):
        self.assertEqual(0,div(1,5))
    def test_add(self):
        self.assertEqual(3,add(1,2))

unittest.main()

在执行上述语句之后,返回如下信息,然后退出了python。

>>> unittest.main()
.F
======================================================================
FAIL: test_div (__main__.TestTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "<stdin>", line 3, in test_div
AssertionError: 0 != 0.2

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

需要注意的是,在调用测试类的时候,可以直接实用unittest.main函数。其中assertEqualTestCase中封装的一个断言函数,当输入变量不相等时会报出断言错误。

断言函数

其实掌握了assertEqual,就可以满足很多的测试需求了,而TestCase中提供了很多断言方法,有些可成对出现,下表中称之为逆断言,若断言为assertXXX,则其逆断言写为assertNotXXX,参数相同。如果断言为真,则逆断言为假。

用于判断相等 真值情况 逆断言
assertEqual(a, b) a == b assertNotEqual
assertTrue(x) x
assertFalse(x) !x
assertIs(a, b) a is b assertIsNot
assertIsNone(x) x is None assertIsNotNone
assertIn(a, b) a in b assertNotIn
assertIsInstance(a, b) isinstance assertNotIsInstance

其中,assertEqual可以自动选用不同类型的比较方法,这些方法为

Method 用作比较 Method 用作比较
assertMultiLineEqual 字符串 assertSequenceEqual 序列
assertListEqual 列表 assertTupleEqual 元组
assertSetEqual 集合 assertDictEqual 字典

此外,还可以通过addTypeEqualityFunc来注册新的比较函数,从而可以让assertEqual对任何对象以任意的规则进行比较。

下面是用于比较大小的断言函数

用于比较 真值情况 逆断言
assertAlmostEqual(a, b) round(a-b, 7) == 0 assertNotAlmostEqual
assertGreater(a, b) a > b
assertGreaterEqual(a, b) a >= b
assertLess(a, b) a < b
assertLessEqual(a, b) a <= b
assertRegex(s, r) r.search(s) assertNotRegex(s, r)
assertCountEqual(a, b) a和b中的相同元素个数相同

其中assertAlmostEqualassertNotAlmostEqual中,调节二者相似程度的参数为places,默认为7。

下面的这些断言用于测试函数,其中,exc和warn表示当函数测试失败时弹出的报错和警告信息。

测试内容
assertRaises(exc, fun, *args, **kwds) fun(*args, **kwds) 报错
assertRaisesRegex(exc, r, fun, *args, **kwds) fun(*args, **kwds) 报错且报错信息匹配r
assertWarns(warn, fun, *args, **kwds) fun(*args, **kwds) 警告
assertWarnsRegex(warn, r, fun, *args, **kwds) fun(*args, **kwds) 警告且报错信息匹配r
assertLogs(logger, level) with block中记录最低级别日志
assertNoLogs(logger, level)

通过dir查看,除了一些已经弃用的断言函数之外,还有一个assertDictContainsSubset,并没有在官方文档上找到是干嘛的。

所有这些断言函数都有参数msg,用以输出报错信息。在TestCase类中有一个成员变量longMessage,若longMessageFalse,则在遇到标准错误时将会输出自定义报错信息;否则的话自定义信息将会追加在标准错误信息的末尾。

maxDiff变量则会调整输出信息的尺寸,默认为80*8个字符。

run过程

可以认为TestCase中的run函数是主要执行测试的函数。

查看run函数的源码,发现这个函数还有一个输入参数为result,若未定义,则会通过调用defaultTestResult()新建一个临时对象,来启动测试程序。

run的执行过程中,会优先考虑当前测试是否启用了skip,若__unittest_skip__True,则会return。

如果未被忽略,则会进行测试,而在测试前后,会分别调用setUp以及tearDown,重载这两个函数可以直观地理解二者的作用时机

在编写自己的测试类的时候,需要继承TestCase,如果想在每次测试前后对测试环境进行初始化和恢复,则需要重载setUp以及tearDown

import unittest
class TestTest(unittest.TestCase):
    def test_div(self):
        print("test div")
        self.assertEqual(0.2,div(1,5))
    def test_add(self):
        print("test add")
        self.assertEqual(3,add(1,2))
    def setUp(self):
        print("test start")
    def tearDown(self):
        print("test end")

这时再进行测试,则会得到

>>> unittest.main()
test start
test add
test end
.test start
test div
test end
.
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK

可见,每个测试函数在执行之前,都会调用一次setUp,而测试函数结束时则会调用tearDown。如果想只调用一次,则需重载setUpClass以及tearDownClass

tearDown之后,会执行doCleanups,这个函数是更加强大的清除工具,无论测试是否成功,均会执行。其执行的功能,则通过addCleanup来添加。这两个方法同样有类的形式:doClassCleanupsaddClassCleanup

##其他方法和变量

  • countTestCases():返回当前对象的测试个数
  • id():返回当前测试case的字符串标识
  • shortDescription():返回当前测试的一个描述
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐