抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

程序的必经之路:测试

测试分为 单元测试组件测试系统测试性能测试,逐级上升。
所谓的测试驱动开发(TDD:Test-Driven Development),就是说每写完一个小功能,就要做一个完整的单元测试,每次进行改动以后都要进行一次单元测试,以确保功能正常。

每个单元测试都通过以后就可以进行组件测试,所有组件测试都通过就可以进行系统测试,系统测试通过就可以进行性能测试,性能测试类似于“烤机”,测试系统的最大承受能力,承受峰值等等。

单元测试

单元测试就是对一个模块、一个函数或者一个类进行正确性检验的检测工作
举个栗子:

对一个求绝对值函数 abs(num),可以编写一下几个测试用例:

  1. 输入正数 如 14.15.9,期待返回正整数 14.15.9
  2. 输入负数 如 -1.5-3.720,期待返回正整数 1.53.720
  3. 输入 0,期待返回 0
  4. 输入非数值类型 如 None[]{},期待抛出TypeError

将上面4个测试用例放到一个测试模块里,就是一个完整单元测试。
单元测试能通过了,说明这个函数功能正常,如果不通过,要么函数有问题,要么测试用例有问题。
所以要修复直到单元测试能够通过。

这样做的好处是,如果我们对abs()做了修改,只要再进行一次单元测试,可以通过,就说明修改没有影响函数的功能。如果不通过则要找出问题,修改到通过单元测试为止。极大程度上确保该模块行为仍然是正确的。

文档测试

一个函数、模块、类的第一个匿名字符串,就是文档。如

1
2
3
4
5
6
7
8
9
10
11
12
def func():
'''
这里是文档
'''
pass


class cls:
'''
这里是文档
'''
pass

文档的内容可以作为测试集来进行测试。
第一步:编写文档。文档中 >>>的行会被执行,这与在交互模式下执行语句的相同的。
第二步:if __name__ == '__main__': import doctest; doctest.testmod()
第三步:运行文件

例如上面的绝对值函数abs()可以这样写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def abs(num):
'''
The function will return the absolute value of num.

>>> abs(11)
11
>>> abs(-41)
41
>>> abs(0)
0
>>> abs('a')
Traceback (most recent call last):
...
TypeError: '>=' not supported between instances of 'str' and 'int'
'''
return n if n >= 0 else (-n)


if __name__ == '__main__':
import doctest
doctest.testmod()

文档中以 >>> 表示测试用例,并在下行写出结果。如果测试结果正确,则什么也不会输出。

小结

doctest非常有用,不但可以用来测试,还可以直接作为示例代码。通过某些文档生成工具,就可以自动把包含doctest的注释提取出来。用户看文档的时候,同时也看到了doctest。

Unittest

  1. 环境搭建:Python已内置Unittest框架,直接import unittest
  2. 四大组件:
    1. test fixture:setUp(前置条件)、tearDown(后置条件),用于初始化测试用例及清理和释放资源
    2. test case:测试用例,通过继承unittest.TestCase实现用例的继承。在Unittest中,测试用例都是通过test前缀或后缀来识别的。
      def test_xxx(self)def xxx_test(self)
    3. test suite:测试套件,即测试用例的集合。
    4. test runner:运行器,一般通过runner来调用suite去执行测试。
  3. 运行机制:通过在main函数中,调用unittest.main()运行所有内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import unittest

class forTest(unittest.TestCase):
# 初始化
def setUp(self) -> None:
print('setUp')

# 释放
def tearDown(self) -> None:
print('tearDown')

# 测试用例1
def test_a(self):
print('a')

# 测试用例2
def test_b(self):
print('b')


if __name__ == '__main__'
unittest.main()

--------------------------------------------------

# Output:
setUp
a
tearDown
setUp
b
tearDown

哔哔