文章总览图
使用Python模块unittest中的工具来测试代码。
一,测试函数
函数get_formatted_name()将名和姓合并成姓名,在名和姓之间加上一个空格,并将它们的首字母都大写,再返回结果。
先创建一个脚本:
再创建第二个脚本:
输出:
1.单元测试和测试用例
单元测试用于核实函数的某个方面没有问题。测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。对于大型项目,要实现全覆盖可能很难。最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。
2.可通过的测试
测试用例创建后,再添加针对函数的单元测试就很简单了。要为函数编写测试用例,可先导入模块unittest以及要测试的函数,再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。
导入了模块unittest和要测试的函数get_formatted_name()。创建一个NamesTestCase的类,用于包含一系列针对get_formatted_name()的单元测试。可随便给这个类命名,取个与这项测试有关的名字,并包含字样Test。这个类必须继承unittest.TestCase类,这样Python才知道如何运行你编写的测试。
NamesTestCase只包含一个方法,用于测试get_formatted_name()的一个方面。
将这个方法命名为:
test_first_last_name()
因为我们要核实的是只要名和姓的姓名能否被正确地格式化。运行testname_function.py时,所有以test打头的方法都将自动运行。
在这个方法中,我们调用了要测试的函数,并存储了要测试的返回值。
使用实参'janis'和'joplin'调用get_formatted_name(),并将结果存储到变量formatted_name中。
使用了unittest类最有用的功能之一:一个断言方法。断言方法用来核实得到的结果是否与期望的结果一致。
get_formatted_name()应返回这样的姓名,即名和姓的首字母为大写,且它们之间有一个空格。
因此我们期望formatted_name的值为Jains Joplin。
为检查是否确实如此,调用unittest的方法 assertEqual(),并向它传递formatted_name和 'Janis Joplin'。
代码行:
self.assertEqual(formatted_name,'Janis Joplin')
意思是说:“将formatteed_name的值同字符串'Janis Joplin'进行比较,如果它们相等,就显示OK,如果它们不相等,就说明一下。
输出:
第1行的句点表明有一个测试通过了。接下来的一行指出Python运行了一个测试,消耗时间不到0.0001秒。OK表明该测试用例中的所有单元测试都通过了。
3.不能通过的测试
能正确处理包含中间名的姓名,但对其进行测试时,发现它再也不能正确地处理只有名和姓的姓名。
先创建一个脚本:
再创建第二个脚本:
输出:
因为测试未通过时,第1行输出只有一个字母E,它指出测试用例中有一个单元测试导致了错误。
NamesTestCase中:
test_first_last_name()导致了错误。
测试用例包含众多单元测试时,知道那个测试未通过很重要。
标准的traceback。
它指出函数调用:
get_formatted_name('jains','joplin')有问题,因为它缺少一个必不可少的位置实参。
4.测试未通过咋办
不用修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。
要将中间名设置为可选的,可在函数定义中将形参middle移到形参列表末尾,并将其默认值指定为一个空字符串。还要添加一个if测试,以便根据是否提供了中间名相应地创建姓名。
先创建一个脚本:
再创建第二个脚本:
输出:
在get_formatted_name()的这个新版本中,中间名可选的。向这个函数传递了中间名(if middle:),姓名将包含名、中间名、姓,否则姓名将只包含名和姓。
5.添加新的测试
添加方法名为:
test_first_last_middle_name()
方法名必须以test_打头,这样它才会在运行 test_name_function.py 时自动运行。在TestCase类中使用很长的方法名是可以的。这些方法的名称必须是描述性的,这才能让你明白测试未通过时的输出。这些方法由Python自动调用,根本不用编写调用它们的代码。
测试函数get_formatted_name(),使用名、姓和中间名调用它,再使用asserEqual()检查返回的姓名是否与预期的姓名(名、中间名和姓)一致。
输出:
二,测试类
针对类的测试通过了,就能确信对类所做的改进没有意外地破坏其原有的行为。
1.各种断言方法
Python在unittest.TestCase类中提供了很多断言方法。6个常用的断言方法。使用这些方法可核实返回的值等于或不等于预期的值、返回的值为True或False、返回的值在列表中或不在列表中。
unittest Module中的断言方法
2.一个要测试的类
类的测试,大部分都是测试类中方法的行为。
首先编写一个AnonymousSurey类。这个类首先存储了一个指定的调查问题,并创建了一个空列表,用于存储答案。这个类包含打印调查问题的方法,在答案列表中添加新答案的方法以及存储在列表中的答案都打印出来的方法。
要创建这个类的实例,只需提供一个问题即可。有了表示调查的实例后,就可使用show_question()来显示其中的问题,可使用store_response()来存储答案,并使用show_results()来显示调查结果。
编写一个脚本:
编写第二个脚本:
输出:
根据问题创建了一个AnonymousSurvey对象。
AnonymousSurvey类可用于进行简单的匿名调查。
3.测试AnonymousSurvey类
对AnonymousSurvey类的行为的一个方面进行验证:如果用户面对调查问题时只提供了一个答案,这个答案也能被妥善地存储。将这个答案被存储后,使用方法assertIn()来核实它包含在答案列表中。
对于这个方法,一个描述性名称是test_store_single_response()。如果测试未通过,通过输出中的方法名得知,在存储单个调查方案方面存在问题。
输出:
4.方法setUp()
在test_survey.py中,在每个测试方法中都创建了一个AnonymousSurvey实例,并在每个方法中都创建了答案。unittest.TestCase类包含方法setUp(),只需创建这些对象1次,并在每个测试方法中使用它们。如果在TestCase类中包含了方法setUp(),Python将先运行它,再运行各个以test_打头的方法。编写的每个测试方法中都可使用在方法setUp()中创建的对象了。
方法setUp()做了2件事:创建1个调查对象。创建1个答案列表。存储这两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。
方法setUp()根据类高效地创建实例并设置其属性,以便在类的所有测试方法中都可使用它们。
输出:
运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试通过时打印一个句点。测试引发错误时打印一个E。测试导致断言失败时,打印一个F。这就是运行测试用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。