Python标准库并不包含pytest,因此使用时需要先使用在终端使用如下命令来安装这个第三方包。安装完成后直接运行pytest可以查看到是否安装成功(在Linux系统上可能需要python3 -m pytest)。
$ python3 -m pip install --user pytest
或者
$ pip install pytest
测试文件的名称很重要,必须以test_打头。当测试文件所在的文件夹下打开终端运行pytest进行测试时,它将查找以test_打头的文件,并运行其中的所有测试。 另外pytest命令后可以加测试文件的名称作为参数,如果不指定任何参数的话,pytest将运行它在当前目录中找到的所有测试。
测试函数示例
#待测试文件 name_function.py
def get_formatted_name(first, last):
"""生成格式规范姓名"""
full_name = f"{first} {last}"
return full_name.title()
#测试文件 test_name_function.py
#测试函数也必须以test_打头,在测试过程中,pytest会调用并运行所有以test_打头的函数。
def test_first_last_name():
"""测试用例"""
formatted_name = get_formatted_name('janis', 'Joplin')
#如果断言正确,表示测试通过;如果断言不正确,表示测试未通过
assert formatted_name == 'Janis Joplin'
测试类示例
# 被测试类
class AnonymousSurvey:
"""收集匿名调查问卷的答案"""
def __init__(self, question):
"""存储一个问题,并为存储答案做准备"""
self.question = question # 存储一个调查问题
self.responses = [] # 创建一个空列表,用于存储答案
def show_question(self):
"""显示问卷调查"""
print(self.question) # 打印调查问题
def stroe_response(self, new_response):
"""存储单份调查答卷"""
self.responses.append(new_response) # 在答案列表中添加新新答案
def show_results(self):
"""显示收集到的所有答案"""
print("Survey results:")
for response in self.responses:
print(f"- {response}") # 将存储在答案列表中的答案打印出来
# # 定义一个问题并创建一个表示调查的AnonymousSurvey对象
# question = "What language did you first to learn to speak?"
# language_survey = AnonymousSurvey(question)
# # 显示问题,并存储答案
# language_survey.show_question()
# print("Enter 'q' at any time to quit.\n")
# while True:
# response = input("Language: ")
# if response == 'q':
# break
# language_survey.stroe_response(response)
# # 显示调查结果
# print("\nThank you to do the survey!")
# language_survey.show_results()
下面是一个测试用例,可以发现若使用这种方式进行测试的话,在每个测试函数中都会创建一个AnonymousSurvey实例。这对于包含数十乃至数百个测试的项目来说是个大问题,重复代码就太多了。
# 测试用例
from survey import AnonymousSurvey
def test_store_single_response():
"""测试单个答案会被妥善地存储"""
question = "What language did you first to learn to speak?"
# 要测试类的行为就要创建其实例
language_survey = AnonymousSurvey(question)
language_survey.stroe_response('English')
assert 'English' in language_survey.responses
def test_store_three_response():
"""测试三个答案会被妥善地存储"""
question = "What language did you first to learn to speak?"
# 要测试类的行为就要创建其实例
language_survey = AnonymousSurvey(question)
responses = ['English', 'Chinese', 'Spanish']
for response in responses:
language_survey.stroe_response(response)
for response in responses:
assert response in language_survey.responses
为了避免在每个测试函数中都创建一个AnonymousSurvey实例。在测试中可以使用夹具(fixture)帮助我们搭建测试环境。这通常意味着创建可供多个测试用例使用的资源。在pytest中,要创建夹具,可编写一个使用装饰器@pytest.fixture装饰的函数。装饰器(decorator)是放在函数定义前的指令。在运行函数前,Python将该指令应用于函数,以修改函数代码的行为。这个听起来很复杂,但是不用担心:即便不知道如何编写装饰器,也可使用第三方包中的装饰器。
下面使用夹具创建一个AnonymousSurvey实例,让上面test_survey.py中的二个测试函数都可以使用它。
# 测试用例。下面的二个测试函数都有一个名为language_survey的形参。当测试函数的一个形参与
# 应用了装饰器@pytest.fixture的函数(夹具)同名时,将自动运行夹具,并将夹具返回的值传递给
# 测试函数。在这个实例中,language_survey()函数向test_store_single_response()和
# test_store_three_response()提供了一个language_survey实例。
import pytest #此时需要导入pytest,因为我们使用了其中定义的一个装饰器@pytest.fixture
from survey import AnonymousSurvey
@pytest.fixture # 将装饰器@pytest.fixture应用于新函数language_survey()
def language_survey():
"""一个可供所有测试函数使用的AnonymousSurvey实例"""
question = "What language did you first to learn to speak?"
language_survey = AnonymousSurvey(question)
return language_survey
def test_store_single_response(language_survey):
"""测试单个答案会被妥善地存储"""
language_survey.stroe_response('English')
assert 'English' in language_survey.responses
def test_store_three_response(language_survey):
"""测试三个答案会被妥善地存储"""
responses = ['English', 'Chinese', 'Spanish']
for response in responses:
language_survey.stroe_response(response)
for response in responses:
assert response in language_survey.responses
由此可见,在想要使用夹具来消除重复代码时,可编写一个函数来生成供多个测试函数使用的资源,再对这个函数应用装饰器 @pytest.fixture,并让使用该资源的每个测试函数都接受一个与该函数同名的形参。这样,测试将更简洁。