forked from ethan-funny/explore-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.md
More file actions
180 lines (130 loc) · 6.52 KB
/
Copy pathREADME.md
File metadata and controls
180 lines (130 loc) · 6.52 KB
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# 单元测试
软件系统的开发是一个很复杂的过程,随着系统复杂性的提高,代码中隐藏的 bug 也可能变得越来越多。为了保证软件的质量,测试是一个必不可少的部分,甚至还有**测试驱动开发(Test-driven development, TDD)**的理念,也就是先测试再编码。
在计算机编程中,**单元测试(Unit Testing)**又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作,所谓的单元是指一个函数,一个模块,一个类等。
在 Python 中,我们可以使用 `unittest` 模块编写单元测试。
下面以[官方文档](https://docs.python.org/2/library/unittest.html)的例子进行介绍,该例子对字符串的一些方法进行测试:
```python
# -*- coding: utf-8 -*-
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO') # 判断两个值是否相等
def test_isupper(self):
self.assertTrue('FOO'.isupper()) # 判断值是否为 True
self.assertFalse('Foo'.isupper()) # 判断值是否为 False
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)
```
在上面,我们定义了一个 TestStringMethods 类,它从 `unittest.TestCase` 继承。注意到,我们的方法名都是以 `test` 开头,表明该方法是测试方法,不以 `test` 开头的方法测试的时候不会被执行。
在方法里面,我们使用了`断言(assert)`判断程序运行的结果是否和预期相符。其中:
- `assertEqual` 用于判断两个值是否相等;
- `assertTrue/assertFalse` 用于判断表达式的值是 True 还是 False;
- `assertRaises` 用于检测异常;
断言方法主要有三种类型:
- 检测两个值的大小关系:相等,大于,小于等
- 检查逻辑表达式的值:True/Flase
- 检查异常
下面列举了部分常用的断言方法:
| Method | Checks that |
| :--- | :--- |
| assertEqual(a, b) | a == b |
| assertNotEqual(a, b) | a != b |
| assertGreater(a, b) | a > b |
| assertGreaterEqual(a, b) | a >= b |
| assertLess(a, b) | a < b |
| assertLessEqual(a, b) | a <= b |
| assertTrue(x) | bool(x) is True |
| assertFalse(x) | bool(x) is False |
| assertIs(a, b) | a is b |
| assertIsNot(a, b) | a is not b |
| assertIsNone(x) | x is None |
| assertIsNotNone(x) | x is not None |
| assertIn(a, b) | a in b |
| assertNotIn(a, b) | a not in b |
| assertIsInstance(a, b) | isinstance(a, b) |
| assertNotIsInstance(a, b) | not isinstance(a, b) |
现在,让我们来运行上面的单元测试,将上面的代码保存为文件 `mytest.py`,通过 `-m unittest` 参数运行单元测试:
```
$ python -m unittest mytest
test_isupper (mytest.TestStringMethods) ... ok
test_split (mytest.TestStringMethods) ... ok
test_upper (mytest.TestStringMethods) ... ok
```
执行结果:
```python
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
```
上面的结果表明测试通过,我们也可以加 `-v` 参数得到更加详细的测试结果:
```python
$ python -m unittest -v mytest
test_isupper (mytest.TestStringMethods) ... ok
test_split (mytest.TestStringMethods) ... ok
test_upper (mytest.TestStringMethods) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
```
上面这种运行单元测试的方法是我们推荐的做法,当然,你也可以在代码的最后添加两行:
```python
if __name__ == '__main__':
unittest.main()
```
然后再直接运行:
```python
$ python mytest.py
```
# setUp 和 tearDown
在某些情况下,我们需要在每个测试方法执行前和执行后做一些相同的操作,比如我们想在每个测试方法执行前连接数据库,执行后断开数据库连接,为了避免在每个测试方法中编写同样的代码,我们可以使用 setUp 和 tearDown 方法,比如:
```python
# -*- coding: utf-8 -*-
import unittest
class TestStringMethods(unittest.TestCase):
def setUp(self): # 在每个测试方法执行前被调用
print 'setUp, Hello'
def tearDown(self): # 在每个测试方法执行后被调用
print 'tearDown, Bye!'
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO') # 判断两个值是否相等
def test_isupper(self):
self.assertTrue('FOO'.isupper()) # 判断值是否为 True
self.assertFalse('Foo'.isupper()) # 判断值是否为 False
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)
```
看看执行结果:
```
$ python -m unittest -v mytest
test_isupper (mytest.TestStringMethods) ... setUp, Hello
tearDown, Bye!
ok
test_split (mytest.TestStringMethods) ... setUp, Hello
tearDown, Bye!
ok
test_upper (mytest.TestStringMethods) ... setUp, Hello
tearDown, Bye!
ok
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
```
# 小结
- 通过从 `unittest.TestCase` 继承来编写测试类。
- 使用断言方法判断程序运行的结果是否和预期相符。
- setUp 在每个测试方法执行前被调用,tearDown 在每个测试方法执行后被调用。
# 参考资料
- [unittest — Unit testing framework — Python 2.7.12 documentation](https://docs.python.org/2/library/unittest.html)
- [python单元测试unittest | Lucia Garden](http://luciastar.com/2016/05/16/python%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95unittest/)
- [单元测试 - 廖雪峰的官方网站](http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00140137128705556022982cfd844b38d050add8565dcb9000)
- [单元测试 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95)
- [“单元测试要做多细?” | 酷 壳 - CoolShell.cn](http://coolshell.cn/articles/8209.html)