首页 > Python基础教程 >
-
提高你的Python能力:理解单元测试(2)
这个文件通过一个test case:?test_is_five_prime. 创建了一个单元测试。通过Python内嵌的一个测试框架 unittest。当unittest.main()被调用时,任何一个以test开头命名的成员函数将被运行,他们是unittest.TestCase的一个派生类,并且是断言检查的。如果我们通过输入python test_primes.py来运行测试,我们能够看到unittest框架在控制台上 的输出:
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 |
单独的“E”表示的是我们单元测试的结果(如果它成功了,会打印出一个“.”)。我们可以看到我们的测试失败了,以及导致失败的那行代码,还有任何引发的异常信息。
为什么要测试?
在我们继续那个例子之前,要问个很重要的问题:“为什么测试对我来说有价值”?这是个公平的问题,也是那些对于代码测试不熟悉的人常问的问题。毕竟,测试需要一定的时间,而我们完全可以用这些时间去编代码,为什么要测试而不是去做那些最有生产效率的事?
有很多答案可以有效的回答这个问题,我列出了以下几点:
测试可以保证你的代码在一系列给定条件下正常工作
测试确保了一系列条件下的正确性。语法错误基本上一定通过测试被查出来,一个代码单元的基本的逻辑也可以通过测试被检测出来,以确保一定条件下的正确性。再次,它不是要证明代码是在任何条件下都正确的。我们只是简单的瞄准了一套比较完整的可能的条件(例如,你可以写一个测试来监测当你调用my_addition_function(3, 'refrigerator), 的时候,但你不必为每个参数检测所有可能的字符串)
测试允许人们确保对代码的改动不会破坏现有的功能
重构代码时,这一点特别有用。如果没有测试到位,你就没法保证你的代码的改变没有破坏之前工作正常的东西。如果你希望更改或重写你的代码,并希望不会破坏任何东西,适当的单元测试是很必要的。
测试迫使人们在不寻常条件的情况下思考代码,这可能会揭示出逻辑错误
编写测试强迫你去思考在非正常条件下你的代码可能遇到的问题。在上面的例子中,my_addition_function函数可以将两个数字相加。测试基本正确性的简单测试将调用my_addition_function(2,2),并断言说结果是4。然而,进一步的测试可能会通过调用my_addition_function(2.0,2.0)来测试该功能是否能正确进行浮点数的运算。防御性的编码原则表明你的代码应该能够在非法输入的情况下正常失效,因此测试时,当字符串类型被作为参数传递到函数中时应当抛出一个异常。
良好的测试要求模块化,解耦代码,这是一个良好的系统设计的标志
单元测试的整体做法是通过代码的松散耦合使其变得更容易。如果你的应用程序代码直接调用数据库,例如,测试你应用程序的逻辑依赖于一个有效的数据库连接,并且测试数据要存在于数据库中。另一方面,隔离了外部资源的代码在测试过程中更容易被模拟对象所替代。出于必要,(人们)设计的有测试能力的应用程序最终采用了模块化和松散耦合。
单元测试的剖析
通过继续之前的例子,我们将看到如何编写并组织单元测试。回想一下,primes.py包含以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
def is_prime(number): """Return True if *number* is prime.""" for element in range (number): if number % element = = 0 : return False return True def print_next_prime(number): """Print the closest prime number larger than *number*.""" index = number while True : index + = 1 if is_prime(index): print (index) |