编写函数或类时,还可为其编写测试。通过测试,可确定代码面对各种输入都能够按要求的那样工作。测试让你深信,即便有更多人使用你的程序,它也能正确地工作。在程序中添加新代码时,也可以对其进行测试,确认不会破坏程序既有的行为。
学习如何使用Python模块unittest中的工具来测试代码,还将学习编写测试用例,核实一系列输入都将得到预期的输出。你将看到测试通过了是什么样子,测试未通过又是什么样子,还将知道测试未通过如何有助于改进代码。你将学习如何测试函数和类,并将知道该为项目编写多少个测试。
测试函数
def get_formatted_name(first, last):
"""生成整洁的姓名。"""
full_name = f"{first} {last}"
return full_name.title()
from name_function import get_formatted_name
print("Enter 'q' at any time to quit.")
while True:
first = input("\nPlease give me a first name: ")
if first == 'q':
break
last = input("Please give me a last name: ")
if last == 'q':
break
formatted_name = get_formatted_name(first, last)
print(f"\tNeatly formatted name: {formatted_name}.")
输出:
Enter 'q' at any time to quit.
Please give me a first name: liu
Please give me a last name: junlong
Neatly formatted name: Liu Junlong.
Please give me a first name: q
模块unittest
unittest模块中的断言方法:
Python在unittest.TestCase 类中提供了很多断言方法,断言方法检查你认为应该满足的条件是否确实满足,应该满足的条件实际上并不满足,Python将引发异常。
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 中
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')
if __name__ == '__main__':
unittest.main()
运行结果:
st_name_function.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
第一行的 ‘ . ’ 表明有一个测试通过了。接下来的一行指出Python运行了一个测试,消耗的时间不到0.001秒。最后的OK 表明该测试用例中的所有单元测试都通过了
def get_formatted_name(first, middle, last):
"""生成整洁的姓名。"""
full_name = f"{first} {middle} {last}"
return full_name.title()
执行测试用例输出:
E
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase.test_first_last_name)
能够正确地处理像Janis Joplin这样的姓名吗?
----------------------------------------------------------------------
Traceback (most recent call last):
File "d:\pytest\alient_invasion\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'
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
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()
再次执行测试用例:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
测试通过了,确定get_formatted_name() 又能正确处理简单的姓名后,我们再编写一个测试,用于测试包含中间名的姓名。
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')
def test_first_last_middle_name(self):
"""能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗?"""
formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')
if __name__ == '__main__':
unittest.main()
输出结果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
显示有两个单元测试pass了。
测试类
类的测试与函数的测试相似,你所做的大部分工作是测试类中方法的行为。不过还是存在一些不同之处,下面编写一个要测试的类。来看一个帮助管理匿名调查的类:
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}")
from survey import AnonymousSurvey
# 定义一个问题,并创建一个调查。
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
# 显示问题并存储答案。
my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
response = input("Language: ")
if response == 'q':
break
my_survey.store_response(response)
# 显示调查结果。
print("\nThank you to everyone who participated in the survey!")
my_survey.show_results()
What language did you first learn to speak?
Enter 'q' at any time to quit.
Language: english
Language: china
Language: q
Thank you to everyone who participated in the survey!
Survey results:
- english
- china
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()
执行结果:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
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.000s
OK
方法setUp()
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()
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
两个测试都通过了。