首页 > Python基础教程 >
-
提高你的Python能力:理解单元测试(3)
同时,文件test_primes.py包含如下代码:
1
2
3
4
5
6
7
8
9
|
import unittest from primes import is_prime class PrimesTestCase(unittest.TestCase): """Tests for `primes.py`.""" def test_is_five_prime( self ): """Is five successfully determined to be prime?""" self .assertTrue(is_prime( 5 )) if __name__ = = '__main__' : unittest.main() |
做出断言
unittest是Python标准库中的一部分,并且也是我们开始“单元测试之旅”的一个好的起点。一个单元测试中包括一个或多个断言(一些声明被测试代码的一些属性为真的语句)。会想你上学的时候“断言”这个词的字面意思就是“陈述事实”。在单元测试中,断言也是同样的作用。
self.assertTrue 更像是自我解释。它能声明传递过去的参数的计算结果为真。unittest.TestCase类包含了许多断言方法,所以一定要检查列表并选择合适的方法进行测试。如果在每个测试中都用到assertTrue的话,则应该考虑一个反模式,因为它增加了测试中读者的认知负担。正确使用断言的方法应当是使测试能够明确说明究竟是什么在被断言(例如,很明显?,只需扫一眼assertIsInstance 的方法名,就知道它要说明的是其参数)。
每个测试应该测试一个单独、有具体特性的代码,并且应该被赋予相关的命名。就单元测试发现机制的研究表明(主要在Python2.7+和3.2+版本中),测试方法应该以test_为前缀命名。(这是可配置的,但是其目的是鉴别测试方法和非测试的实用方法)。如果我们把test_is_five_prime 的命名改为is_five_prime的话,运行python中的test_primes.py时会输出如下信息:
1
2
3
4
|
$ python test_primes.py ---------------------------------------------------------------------- Ran 0 tests in 0.000s OK |
不要被上面信息中的“OK”所糊弄了,只有当什么测试都没真正运行的时候才会显示出“OK”!我认为一个测试也没跑其实应该显示个报错的,但是个人感觉放在一边,这是一个你应该注意是行为,尤其是当通过程序运行来检查测试结果的时候(例如,一个持续的集成工具,像TracisCI)。
异常
让我们回到test_primes.py的实际内容中去,回忆一下运行python test_primes.py指令后的输出结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
$ python test_primes.py E ====================================================================== ERROR: test_is_five_prime (__main__.PrimesTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "test_primes.py" , line 8, in test_is_five_prime self.assertTrue(is_prime(5)) File "/home/jknupp/code/github_code/blug_private/primes.py" , line 4, in is_prime if number % element == 0: ZeroDivisionError: integer division or modulo by zero ---------------------------------------------------------------------- Ran 1 test in 0.000s |
这些输出告诉我们,我们一个测试的结果失败并不是因为一个断言失败了,而是因为出现了一个未捕获的异常。事实上,由于抛出了一个异常,unittest框架并没有能够运行我们的测试就返回了。
这里的问题很明确:我们使用的求模运算的计算范围中包括了0,因此执行了一个除以0的操作。为了解决这个问题,我们可以很简单的将起始值由0变为2,并指出对0求模是错误的,而对1求模则一直是真(并且一个素数只能被自身和1整除,因此我们无需检查1)。
解决问题
一次失败的测试使我们修改了代码。一旦我们改好了这个错误(将s_prime中的一行改为for element in range(2, number):),我们就得到了如下输出:
1
2
3
4
|
$ python test_primes.py . ---------------------------------------------------------------------- Ran 1 test in 0.000s |