对于程序开发新手来说,一个最常见的困惑是测试的主题。他们隐约觉得“单元测试”是很好的,而且他们也应该做单元测试。但他们却不懂这个词的真正含义。如果这听起来像是在说你,不要怕!在这篇文章中,我将介绍什么是单元测试,为什么它有用,以及如何对Python的代码进行单元测试。

什么是测试?

在讨论为什么测试很有用、怎样进行测试之前,让我们先花几分钟来定义一下“单元测试”究竟是什么。在一般的编程术语中,“测试”指的是通过编写可以调用的代码(独立于你实际应用程序的代码)来帮助你确定程序中是否有错误。这并不能证明你的代码是正确的(在非常有限的情况下这是唯一的可能)。它只是报告了测试者认为的那种情况是否被正确处理了。

注:当我使用“测试”一次时,我指的是“自动化测试”,即这些测试是在机器上运行的。“手动测试”则是一个人运行程序,并与它进行交互,从而发现漏洞,这是个独立的概念。

测试可以检查出什么样的情况呢?语法错误是语言的意外误用,如
 

my_list..append(foo)

后面多余的一个 “.“。逻辑错误是当算法(可以看成是“解决问题的方式”)不正确时引发的。可能程序员忘记Python是“零索引“的并且试图通过写
 

print(my_string[len(my_string)])

(这样会引起IndexError)来打印出一个字符串中的最后一个字符。更大、更系统的错误也可以被检查出来。比如当用户输入一个大于100的数字、或者在网站检索不可用的时候挂起此网站的话,程序会一直崩溃。

这些所有的错误都可以通过对代码的仔细测试检查出来。Unit testing,特指在一个分隔的代码单元中的测试。一个单元可以是整个模块,一个单独的类或者函数,或者这两者间的任何代码。然而,重要的是,测试代码要与我们没有测试到的其他代码相互隔离(因为其它代码本身有错误的话会因此混淆测试结果)。考虑如下例子:
 

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)

你有两个函数,is_prime和print_next_prime。如果你想测试print_next_prime,我们就需要确定is_prime是正确的,因为print_next_prime中调用了这个函数。在这种情况下,print_next_prime函数是一个单元,is_prime函数是另一个单元。由于单元测试每次只测试一个单元,因此我们需要仔细考虑怎样才能准确的测试print_next_prime?(更多的是关于之后怎样实现这些测试)。

因此,测试代码应该长什么样呢?如果上一个例子存在一个叫primes.py的文件中,我们可以把测试代码写在一个叫test_primes.py的文件中。下面是test_primes.py 中的最基本内容,比如下面这个测试样例:
 

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()

这个文件通过一个test case