- 前言
- 一、测试的目的
- 二、测试函数
- 1.断言方法
- 2.可通过的测试
- 3.不可通过的测试
- 4.添加多个测试
- 三、测试类
- 1.简单的测试类
- 2.含多个答案的测试类
- 3.setUp()方法
- 总结
前言
本文的主要内容是Python中测试代码的介绍,包括测试的目的、测试函数以及测试类等内容,文中附有代码以及相应的运行结果辅助理解。
一、测试的目的
测试能够给我们信心,如果你的代码通过了测试,那么即便有再多的人使用你编写的程序,它也能正确地运行。通过测试,可确定代码面对各种输入时都能够按预想的那样工作。
测试是很多初学者都不熟悉的主题,作为初学者,并非必须为你尝试的所有项目编写测试,但参与工作量较大的项目时,应对自己编写的函数和类的重要行为进行测试,这样就能够更加确定自己所做的工作不会破坏项目的其他部分,如果不小心破坏了原来的功能,你马上就会知道,从而能够轻松地修复问题。相比于等到不满意的用户报告bug后再采取措施,在测试未通过时采取措施要容易得多。
二、测试函数
Python标准库中的模块unittest提供了代码测试工具,单元测试用于核实函数的某个方面没有问题,测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试,全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。
1.断言方法Python在unittest.TestCase类中提供了很多断言方法,断言方法的引入是为了检查你认为应该满足的条件是否确实满足,如果该条件确实满足,你对程序行为的假设就得到了确认,就可以确信在该测试中没有错误,如果你认为应该满足的条件实际上并不满足,Python将引发异常。
下面是常见的几个断言方法。
使用这些方法可核实返回的值等于或不等于预期的值、返回的值为True或False、返回的值在列表中或不在列表中,只能在继承unittest.TestCase的类中使用这些方法。
2.可通过的测试写测试代码时,首先要导入模块unittest,如果你待测试的函数在另一个模块,也要将该函数导入;接着创建一个测试类,该类名可以自己起,但是这个类必须继承unittest.TestCase类,因为这样Python才知道如何运行你编写的测试;再接着在该类下写一个方法,用来测试你所写函数的正确性,这个方法需要以test_开头,因为在该模块运行后以test_开头的方法才会自动运行,在这个方法中,调用要测试的函数,并存储了要测试的返回值;然后使用unittest类的功能,即一个断言方法,来核实得到的结果是否与期望的结果一致;最后代码行unittest.main()让Python运行这个文件中的测试。
下面来写一个简单的测试函数例子。
import unittest # 导入模块
def get_full_name(first_name, last_name): # 待测试的函数,也可以将其单独写在一个模块,然后导入
"""输出全名"""
full_name = first_name + ' ' + last_name
return full_name.title()
class NameTestCase(unittest.TestCase): # 该类名可以自己起,这个类必须继承unittest.TestCase类,这样Python才知道如何运行你编写的测试
"""测试函数"""
def test_first_last_name(self): # 运行该模块时,所有以test_打头的方法将自动运行
"""是否能够正确地处理只有名和姓的姓名"""
full_name = get_full_name('kevin', 'durant')
self.assertEqual(full_name, 'Kevin Durant') # 使用断言方法判断函数的输出与我们预想的输出是否一致
unittest.main() # 让Python运行这个文件中的测试
运行结果如下图所示。
在上面的输出结果中,第1行的句点表明有一个测试通过了(有几个句点就通过了几个测试,本例中只有一个测试);接下来的一行指出Python运行了一个测试,消耗的时间不到0.001秒;最后的OK表明该测试用例中的所有单元测试都通过了。
简单修改一下上面的例子,使其为不可通过的测试。
下面是不可通过的测试的例子。
import unittest # 导入模块
def get_full_name(first_name, middle_name, last_name): # 待测试的函数,也可以将其单独写在一个模块,然后导入
"""输出全名"""
full_name = first_name + ' ' + middle_name + ' ' + last_name
return full_name.title()
class NameTestCase(unittest.TestCase): # 该类名可以自己起,这个类必须继承unittest.TestCase类,这样Python才知道如何运行你编写的测试
"""测试函数"""
def test_first_last_name(self): # 运行该模块时,所有以test_打头的方法将自动运行
"""是否能够正确地处理只有名和姓的姓名"""
full_name = get_full_name('kevin', 'durant')
self.assertEqual(full_name, 'Kevin Durant') # 使用断言方法判断函数的输出与我们预想的输出是否一致
unittest.main() # 让Python运行这个文件中的测试
运行结果如下图所示。
在上面的输出结果中,第1行的 E 表明有一个单元测试导致了错误;接下来的一行指出了出错误发生的方法;Traceback这里指明了缺少一个必不可少的位置实参;最后显示了运行测试的时间,还看到了一条消息,它指出整个测试用例都未通过,因为运行该测试用例时发生了一个错误。
在测试不可通过的时候,就要查看自己的函数写得是否正确,有必要的话还要多加一个或几个测试。
再来修改一下这个例子,让其既能通过只有名和姓的测试,也能通过除了名和姓还包含中间名的测试。
下面是包含多个测试的例子。
import unittest # 导入模块
def get_full_name(first_name, last_name, middle_name=''): # 待测试的函数,也可以将其单独写在一个模块,然后导入
"""输出全名"""
if middle_name:
full_name = first_name + ' ' + middle_name + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
return full_name.title()
class NameTestCase(unittest.TestCase): # 该类名可以自己起,这个类必须继承unittest.TestCase类,这样Python才知道如何运行你编写的测试
"""测试函数"""
def test_first_last_name(self): # 运行该模块时,所有以test_打头的方法将自动运行
"""是否能够正确地处理只有名和姓的姓名"""
full_name = get_full_name('kevin', 'durant')
self.assertEqual(full_name, 'Kevin Durant') # 使用断言方法判断函数的输出与我们预想的输出是否一致
def test_first_middle_last_name(self): # 运行该模块时,所有以test_打头的方法将自动运行
"""是否能够正确地处理有名、姓和中间名的姓名"""
full_name = get_full_name('larry', 'jr', 'nance')
self.assertEqual(full_name, 'Larry Nance Jr')
unittest.main() # 让Python运行这个文件中的测试
运行结果如下图所示。
在上面的输出结果中,第1行的两个句点表明有两个测试通过了;接下来的一行指出Python运行了两个测试,消耗的时间不到0.001秒;最后的OK表明该测试用例中的所有单元测试都通过了。
三、测试类
前面是关于函数的测试,下面来进行类的测试,很多程序中都会用到类,因此能够证明类正确地工作相当有用,如果对类的测试通过了,就能确信对类所做的改进没有意外地破坏其原有的行为。
1.简单的测试类下面是一个简单测试类的例子。
import unittest
class FavoriteProgramLanguage(): # 该类可以单独写一个模块然后导入
"""最喜欢的编程语言"""
def __init__(self, question):
"""存储一个问题,并创建一个列表用来存放答案"""
self.question = question
self.answers = [] # 创建一个列表来存放答案
def show_question(self):
"""显示问题"""
print(self.question)
def save_answer(self, answer):
"""将回答存放进列表"""
self.answers.append(answer) # 追加到列表中
class TestFavoriteProgramLanguage(unittest.TestCase):
"""测试类FavoriteProgramLanguage"""
def test_one_answer(self):
"""测试单个回答是否会被正确地存储"""
question = "What program language did you like best?"
my_answer = FavoriteProgramLanguage(question)
my_answer.save_answer('Python')
self.assertEqual(question, my_answer.question) # 查看问题是否相同
self.assertIn('Python', my_answer.answers) # 查看'English'是否在列表中
unittest.main() # 让Python运行这个文件中的测试
运行结果如下图所示。
在上面这个例子中,类的功能是存储问题和该问题的回答,这个简单的测试类是检验单个答案是否成功的存储在了列表中,由测试结果可知,单个答案存储成功。
上面的例子只测试了一个答案的正确性,下面在该例子的基础上修改,使其可以测试多个答案。
下面是含多个答案测试类的例子。
import unittest
class FavoriteProgramLanguage():
"""最喜欢的编程语言"""
def __init__(self, question):
"""存储一个问题,并创建一个列表用来存放答案"""
self.question = question
self.answers = []
def show_question(self):
"""显示问题"""
print(self.question)
def save_answer(self, answer):
"""将回答存放进列表"""
self.answers.append(answer) # 追加到列表中
class TestFavoriteProgramLanguage(unittest.TestCase):
"""测试类FavoriteProgramLanguage"""
def test_one_answer(self):
"""测试单个回答是否会被正确地存储"""
question = "What program language did you like best?"
my_answer = FavoriteProgramLanguage(question)
my_answer.save_answer('Python')
self.assertEqual(question, my_answer.question) # 查看问题是否相同
self.assertIn('Python', my_answer.answers) # 查看'English'是否在列表中
def test_three_answer(self):
"""测试多个回答是否会被正确地存储"""
question = "What program language did you like best?"
my_answer = FavoriteProgramLanguage(question)
languages = ['Python', 'Java', 'C'] # 待测试的列表
for language in languages:
my_answer.save_answer(language) # 将列表中的元素依次追加到列表
self.assertEqual(question, my_answer.question) # 查看问题是否相同
for language in languages:
self.assertIn(language, my_answer.answers) # 查看多个回答是否都在列表中
unittest.main() # 让Python运行这个文件中的测试
运行结果如下图所示。
由运行结果可知,两个测试都通过了。
在上面的例子中,我们在两个测试方法中都创建了一个类的实例,并在每个方法中都创建了答案,这样就显得很繁琐,好在unittest.TestCase类中包含方法setUp(),这让我们只需创建这些对象一次,并在每个测试方法中使用它们。
如果在TestCase类中包含了方法setUp(),Python将先运行它,再运行各个以test_打头的方法。
在上面例子的基础上加入setUp()方法,改进后的代码如下。
import unittest
class FavoriteProgramLanguage():
"""最喜欢的编程语言"""
def __init__(self, question):
"""存储一个问题,并创建一个列表用来存放答案"""
self.question = question
self.answers = []
def show_question(self):
"""显示问题"""
print(self.question)
def save_answer(self, answer):
"""将回答存放进列表"""
self.answers.append(answer) # 追加到列表中
class TestFavoriteProgramLanguage(unittest.TestCase):
"""测试类FavoriteProgramLanguage"""
def setUp(self):
"""创建一个调查对象和一组答案,供使用的测试方法使用"""
question = "What program language did you like best?"
self.my_answer = FavoriteProgramLanguage(question)
self.languages = ['Python', 'Java', 'C']
self.assertEqual(question, self.my_answer.question) # 查看问题是否相同
def test_one_answer(self):
"""测试单个回答是否会被正确地存储"""
self.my_answer.save_answer(self.languages[0]) # 将第一个元素追加到列表
self.assertIn(self.languages[0], self.my_answer.answers) # 查看第一个元素是否在列表中
def test_three_answer(self):
"""测试多个回答是否会被正确地存储"""
for language in self.languages:
self.my_answer.save_answer(language) # 将列表中的元素依次追加到列表
for language in self.languages:
self.assertIn(language, self.my_answer.answers) # 查看多个回答是否在列表中
unittest.main() # 让Python运行这个文件中的测试
运行结果如下图所示。
试想一下,如果在测试类中包含多个方法,那么setUp()方法的作用将会愈加明显。
总结
以上就是Python中测试代码介绍的所有内容了,这部分的内容相对比较简单,在创建的类中继承unittest.TestCase类,并能够熟练正确的运用几个常用的断言方法即可写出测试代码,测试类就是在测试函数基础上的引申。
本文参考书目:Python 编程 :从入门到实践 / (美) 埃里克•马瑟斯(Eric Matthes)著;袁国忠译
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)