logo头像
Snippet 博客主题

Python3 - 单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

如果单元测试通过,说明我们测试的这个函数能够正常工作。如果单元测试不通过,要么函数有bug,要么测试条件输入不正确,总之,需要修复使单元测试能够通过。

这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的。

我们来编写一个stack类,模拟堆栈行为:

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
33
34
35
36
37
38
39
class Stack(object):
"""堆栈"""

def __init__(self):
self.max_size = 3
self.stack_list = []

def size(self):
"""元素大小"""
return len(self.stack_list)

def push(self, temp):
"""添加元素"""
if self.size() < self.max_size:
self.stack_list.append(temp)
else:
pass

def pop(self):
"""推出元素"""
if self.size() > 0:
return self.stack_list.pop()
else:
# raise Exception('没有元素可删除')
return False

def is_none(self):
"""是否为空"""
if self.size() == 0:
return True
else:
return False

def is_full(self):
"""是否为满"""
if self.size() == self.max_size:
return True
else:
return False

为了编写单元测试,我们需要引入Python自带的unittest模块,编写test_stack.py如下:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import unittest

from stack import Stack


class TestClass(unittest.TestCase):
def setUp(self):
"""在每个测试方法前实例化stack"""
self.stack = Stack()

def test_case01(self):
"""测试推入元素顺序"""
self.stack.push(1)
self.stack.push(2)
self.assertTrue(self.stack.stack_list == [1, 2])

def test_case02(self):
"""测试是否能推入超出堆栈原本大小"""
self.stack.push(1)
self.stack.push(2)
self.stack.push(3)
self.stack.push(4)
self.assertTrue(self.stack.size() == self.stack.max_size)
self.assertTrue(self.stack.stack_list == [1, 2, 3])

def test_case03(self):
"""测试有元素时推出元素是先进元素还是后进元素"""
self.stack.push(1)
self.stack.push(2)
self.assertTrue(self.stack.pop() == 2)

def test_case04(self):
"""测试无元素时是否能删除"""
self.assertFalse(self.stack.pop())

def test_case05(self):
"""测试是否为空"""
self.assertTrue(self.stack.is_none())
self.stack.push(123)
self.assertFalse(self.stack.is_none())

def test_case06(self):
"""测试是否为满"""
self.stack.push(1)
self.stack.push(2)
self.assertFalse(self.stack.is_full())
self.stack.push(3)
self.assertTrue(self.stack.is_full())

def test_case07(self):
"""测试大小"""
self.assertIsNone(self.stack.size())
self.stack.push(1)
self.assertTrue(self.stack.size() == 1)


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

编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。

test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。

对每一类测试都需要编写一个test_xxx()方法。

setUp与tearDown

可以在单元测试中编写两个特殊的setUp()tearDown()方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。

setUp()tearDown()方法有什么用呢?设想你的测试需要启动一个数据库,这时,就可以在setUp()方法中连接数据库,在tearDown()方法中关闭数据库,这样,不必在每个测试方法中重复相同的代码:

1
2
3
4
5
6
7
class TestDict(unittest.TestCase):

def setUp(self):
print 'setUp...'

def tearDown(self):
print 'tearDown...'

可以再次运行测试看看每个测试方法调用前后是否会打印出setUp...tearDown...

小结

单元测试可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。

单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。

单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug。

单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。

评论系统未开启,无法评论!