创建name_function.py编写一个函数如下
函数get_formatted_name() 将名和姓合并成姓名:在名和姓之间加上一个空格并将其首字母大写,再返回结果
def get_formatted_name(first, last):
"""生成整洁的姓名。"""
full_name = f"{first} {last}"
return full_name.title()
print(get_formatted_name("zhang","san"))#Zhang San
Python标准库中的模块unittest 提供了代码测试工具。单元测试用于核实函数的某个方面没有问题。测试用例 是一组单元测试,它们一道核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。
创建 test_name_function.py
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""测试name_function.py。"""
def test_first_last_name(self):
"""能够正确地处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
#检查特殊变量__name__ ,这个变量是在程序
#执行时设置的。如果这个文件作为主程序执行,变量__name__ 将
#被设置为'__main__'
if __name__ == '__main__':
unittest.main()
执行结果,OK表示测试通过
Testing started at 11:48 ...
Ran 1 test in 0.001s
OK
假如后来我们修改了get_formatted_name 方法的逻辑增加了新middle name 参数
逻辑如下:
def get_formatted_name(first,middle, last):
"""生成整洁的姓名。"""
full_name = f"{first} {middle} {last}"
return full_name.title()
再次运行 测试代码,结果如下,表名测试失败
Testing started at 11:53 ...
Ran 1 test in 0.004s
FAILED (errors=1)
Traceback (most recent call last):
File "D:\works\pythonworks\testpro\test_name_function.py", line 7, in test_first_last_name
formatted_name = get_formatted_name('janis', 'joplin')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: get_formatted_name() missing 1 required positional argument: 'last'
这个时候就需要看看 需求是什么,是否如果需求必须支持原来 first last 两个参数的情况,就证明目前方法逻辑有问题需要修改。
修改方法逻辑如下
def get_formatted_name(first, last, middle=''):
"""生成整洁的姓名。"""
if middle:
full_name = f"{first} {middle} {last}"
else:
full_name = f"{first} {last}"
return full_name.title()
同时修改测试代码如下,增加三个参数情况的测试
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""测试name_function.py。"""
def test_first_last_name(self):
"""能够正确地处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
def test_first_middle_last_name(self):
"""能够正确地处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis', 'joplin',"may")
self.assertEqual(formatted_name, 'Janis May Joplin')
#检查特殊变量__name__ ,这个变量是在程序
#执行时设置的。如果这个文件作为主程序执行,变量__name__ 将
#被设置为'__main__'
if __name__ == '__main__':
unittest.main()
运行结果
Testing started at 11:59 ...
Ran 2 tests in 0.001s
OK
方法名必须以test_ 打头,这样它才会在我们运行test_name_function.py时自动运行。
下面来编写针对类的测试。很多程序中都会用到类,因此证明你的类能够正确工作大有裨益。
Python在unittest.TestCase 类中提供了很多断言方法,6个常用的如下:
assertEqual(a, b) 核实a == b
assertNotEqual(a, b) 核实a != b
assertTrue(x) 核实x 为True
assertFalse(x) 核实x 为False
assertIn(item , list ) 核实 item 在 list 中
assertNotIn(item , list ) 核实 item 不在 list 中
使用这些方法可核实返回的值等于或不等于预期的值,返回的值为True 或False ,以及返回的值在列表中或不在列表中。只能在继承unittest.TestCase 的类中使用这些方法
在survey.py中编写一个待测试的类,该类用于存储一个问卷问题,及不同人对问题的反馈结果
class AnonymousSurvey:
"""收集匿名调查问卷的答案。"""
def __init__(self, question):
"""存储一个问题,并为存储答案做准备。"""
self.question = question
self.responses = []
def show_question(self):
"""显示调查问卷。"""
print(self.question)
def store_response(self, new_response):
"""存储单份调查答卷。"""
self.responses.append(new_response)
def show_results(self):
"""显示收集到的所有答卷。"""
print("Survey results:")
for response in self.responses:
print(f"- {response}")
test_survey.py中编写测试类
对类的行为的一个方面进行验证:如果用户面对调查问题只提供一个答案,这个答案也能被妥善地存储。为此,我们将在这个答案被存储后,使用方法assertIn() 来核实它确实在答案列表中
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试。"""
def test_store_single_response(self):
"""测试单个答案会被妥善地存储。"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('English')
self.assertIn('English', my_survey.responses)
if __name__ == '__main__':
unittest.main()
运行结果,测试通过
Testing started at 12:16 ...
Launching unittests with arguments python -m unittest test_survey.TestAnonymousSurvey.test_store_single_response in D:\works\pythonworks\testpro
Ran 1 test in 0.001s
OK
Process finished with exit code 0
然后测试当用户提供三个答案时,它们也将被妥善地存储
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试。"""
def test_store_single_response(self):
"""测试单个答案会被妥善地存储。"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('English')
self.assertIn('English', my_survey.responses)
def test_store_three_responses(self):
"""测试三个答案会被妥善地存储。"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
responses = ['English', 'Spanish', 'Mandarin']
for response in responses:
my_survey.store_response(response)
for response in responses:
self.assertIn(response, my_survey.responses)
if __name__ == '__main__':
unittest.main()
验证结果
Ran 2 tests in 0.001s
OK
Process finished with exit code 0
在前面的test_survey.py中,我们在每个测试方法中都创建了一个AnonymousSurvey 实例,并在每个方法中都创建了答案。unittest.TestCase 类包含的方法setUp() 让我们只需创建这些对象一次,就能在每个测试方法中使用。如果在TestCase 类中包含了方法setUp() ,Python将先运行它,再运行各个以test_打头的方法。这样,在你编写的每个测试方法中,都可使用在方法setUp() 中创建的对象。
使用setUp() 来创建一个调查对象和一组答案,供上述测试方法test_store_single_response() 和test_store_three_responses() 使用:
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""针对AnonymousSurvey类的测试。"""
def setUp(self):
"""
创建一个调查对象和一组答案,供使用的测试方法使用。
"""
question = "What language did you first learn to speak?"
self.my_survey = AnonymousSurvey(question)
self.responses = ['English', 'Spanish', 'Mandarin']
def test_store_single_response(self):
"""测试单个答案会被妥善地存储。"""
self.my_survey.store_response(self.responses[0])
self.assertIn(self.responses[0], self.my_survey.responses)
def test_store_three_responses(self):
"""测试三个答案会被妥善地存储。"""
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response, self.my_survey.responses)
if __name__ == '__main__':
unittest.main()
测试结果
Testing started at 12:28 ...
Ran 2 tests in 0.001s
OK