1、编写测试用例
在Pycharm中新建test_sample.py文件如下:其中包含被测函数func和测试用例test_answer,使用assert断言测试预期结果和实际结果。
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
测试用例编写规范:
- 测试文件名必须以“test_”开头或者以”_test”结尾
- 测试类命名以Test开头
- 测试方法必须以“test_”开头
- 测试用例包pakege必须要有__init__.py文件
- 使用assert断言
2、运行测试用例
在Pycharm中使用pytest运行测试用例有两种方式,分别是命令行模式和主函数模式。
1、Terminal终端(命令行模式):
选中test_sample.py文件,鼠标右键Open in | Open in Terminal,打开在Terminal终端窗口,输入命令:pytest
运行结果如下:
C:\Users\057776\PycharmProjects\pytest-demo\testcases>pytest
======================================================================= test session starts ========================================================================
platform win32 -- Python 3.8.8, pytest-7.3.1, pluggy-1.0.0 -- E:\Programs\Python\Python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '7.3.1', 'py': '1.10.0', 'pluggy': '1.0.0'}, 'Plugins': {'html': '3.1.1
', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'allure-pytest': '2.10.0', 'assume': '2.4.3', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jd
k1.8.0_271', 'foo': 'bar'}
rootdir: C:\Users\057776\PycharmProjects\pytest-demo
configfile: pytest.ini
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, allure-pytest-2.10.0, assume-2.4.3, requests-mock-1.7.0
collected 1 item
test_sample.py::test_answer FAILED
============================================================================= FAILURES =============================================================================
___________________________________________________________________________ test_answer ____________________________________________________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:18: AssertionError
===================================================================== short test summary info ======================================================================
FAILED test_sample.py::test_answer - assert 4 == 5
======================================================================== 1 failed in 0.56s =========================================================================
C:\Users\057776\PycharmProjects\pytest-demo\testcases>
观察可知,pytest运行测试用例输出的信息包括以下内容:
- Platform(平台):显示正在运行测试的操作系统和Python版本信息。
- Cachedir(缓存目录):显示pytest的缓存目录路径,pytest使用缓存来提高后续运行的效率。
- Metadata(元数据):显示有关项目和环境的元数据信息,例如项目名称、作者、版本等。
- Rootdir(根目录):显示pytest运行的根目录路径,即包含测试用例的目录。
- Configfile(配置文件):显示pytest的配置文件路径,pytest可以使用配置文件来自定义测试行为。
- Plugins(插件):显示已加载的pytest插件列表,插件可以扩展pytest的功能和行为。
2、pytest.main方法(主函数模式):
pytest.main()方法可以作为我们自动化测试项目的测试用例执行入口。
修改上面的test_sample.py文件如下:
import pytest
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
if __name__ == '__main__':
pytest.main()
命令行窗口输出命令:python test_sample.py
C:\Users\057776\PycharmProjects\pytest-demo\testcases>python test_sample.py
======================================================================= test session starts ========================================================================
platform win32 -- Python 3.8.8, pytest-7.3.1, pluggy-1.0.0 -- E:\Programs\Python\Python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '7.3.1', 'py': '1.10.0', 'pluggy': '1.0.0'}, 'Plugins': {'html': '3.1.1
', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'allure-pytest': '2.10.0', 'assume': '2.4.3', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jd
k1.8.0_271', 'foo': 'bar'}
rootdir: C:\Users\057776\PycharmProjects\pytest-demo
configfile: pytest.ini
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, allure-pytest-2.10.0, assume-2.4.3, requests-mock-1.7.0
collected 1 item
test_sample.py::test_answer FAILED
============================================================================= FAILURES =============================================================================
___________________________________________________________________________ test_answer ____________________________________________________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:19: AssertionError
===================================================================== short test summary info ======================================================================
FAILED test_sample.py::test_answer - assert 4 == 5
======================================================================== 1 failed in 0.49s =========================================================================
C:\Users\057776\PycharmProjects\pytest-demo\testcases>
参数说明:
- pytest.main() :无任何参数,会收集当前目录下所有的测试用例,相当于命令行模式下输入命令pytest。
- pytest.main(['test_sample.py']) :一个参数,执行指定文件test_sample.py的所有测试用例。
- pytest.main(['-q','test_sample.py']) :二个参数,参数-q表示安静模式, 不输出环境信息。
pytest.main()源码如下:
def main(
args: Optional[Union[List[str], py.path.local]] = None,
plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None,
) -> Union[int, ExitCode]:
"""Perform an in-process test run.
:param args: List of command line arguments.
:param plugins: List of plugin objects to be auto-registered during initialization.
:returns: An exit code.
"""
pytest.main() 函数接受两个参数:
- args :命令行参数列表,和命令行模式运行时的参数相同,在列表 List 里以字符串 str 的形式,多参数以 “,” 隔开,也可以传入测试case的路径。
- plugins :为插件参数,初始化期间要自动注册的插件对象列表。
3、鼠标右键Run运行(测试运行器):
本地调试代码的时候,我们也可以通过配置默认的测试运行器,选择要运行的.py文件,鼠标右键Run运行。
File | Settings | Tools | Python Integrated Tools
说明:
这种方式可以直接使用pytest来运行指定的文件,方便调试。
3、常见的命令行参数
- -h : 获取帮助信息
- -v : 输出详细信息
- -q : 输出简要信息
- -s : 控制台输出错误信息
- [-k EXPRESSION] : 仅运行与给定子字符串表达式匹配的测试,匹配不区分大小写。
- [-m MARKEXPR] : 执行 mark 标记的测试用例
- [-x, --exitfirst] : 遇到第一个 error 或 failed 的测试用例立即退出
- [--lf, --last-failed] : 重跑上次失败的 tests,如果没有失败就重跑全部
4、测试用例收集规则
默认情况下,pytest会收集当前目录及其子目录下所有以test_*.py或*_test.py文件中,以"test_"开头的测试用例。
Python测试发现的约定是指测试框架(如pytest)遵循的规则和指南,用于自动发现和执行Python项目中的测试用例。这些约定有助于简化测试执行过程,并使组织和有效运行测试更加容易。
在pytest的上下文中,有特定的测试发现约定:
1. 测试函数命名:测试模块中的测试函数应以`test_`为前缀,以被识别为测试用例。pytest根据命名约定识别这些函数,并将它们作为测试套件的一部分执行。
2. 测试文件命名:pytest将与模式`test_*.py`或`*_test.py`匹配的文件视为测试模块。遵循这种命名约定,pytest可以自动发现并执行这些模块中定义的测试用例。
3. 测试类命名:如果你喜欢使用类来组织测试,pytest将以`Test*`或`*Test`的约定命名的类识别为测试类。这些类中的测试方法也应遵循上述测试函数命名约定。
4. 目录结构:pytest从当前目录及其子目录开始搜索测试模块。它递归地探索目录结构,发现测试文件并执行其中的测试用例。因此,将测试文件组织在一个良好定义的目录结构中可以帮助pytest更高效地定位和执行测试。
通过遵循这些约定,你可以利用pytest的测试发现功能,自动找到并执行测试用例,而无需显式指定每个测试用例。这在处理较大的代码库和测试套件时,可以实现更简化和高效的测试过程。
5、测试运行结果标记符
- 点号,表示用例通过
- F 表示失败 Failure
- E 表示用例中存在异常 Error
- S 表示用例被跳过 Skip
- x 小写的 x 表示预期失败 xfail
- X 大写的 X 表示预期失败,但是通过了
6、.pytest_cache缓存目录
pytest运行测试用例后,会在当前执行脚本路径下生成.pytest_cache文件夹,即pytest缓存目录如下:
目录文件说明:
- lastfailed :上一次运行失败的测试用例。
- nodeids :上一次运行的所有测试用例(无论测试用例的执行结果通过还是失败)。
- stepwise :测试用例的路径。
- .gitignore :pytest测试框架 .pytest_cache的自带的 .gitignore 文件。
- CACHEDIR.TAG :pytest创建的缓存目录标签。
- README.md : .pytest_cache 文件夹介绍。
说明:将文件加入到.gitignore中之后,在pycharm中,该文件或文件夹的颜色变为黄色。
7、使用mark标记测试用例
1、使用skip跳过测试用例
使用mark标记可以实现跳过测试用例的功能。通过为测试用例添加`skip`标记,可以将某些测试用例标记为跳过状态,从而在运行测试时跳过这些测试用例。
import pytest
@pytest.mark.skip
def test_example():
# 测试用例的代码
assert 1 + 1 == 2
在上述示例中,`@pytest.mark.skip`装饰器将`test_example()`函数标记为跳过状态。当运行pytest时,这个测试用例将被跳过,不会被执行。
2、使用skipif条件为真时跳过测试用例
除了直接跳过整个测试用例,还可以使用`skipif`标记来根据条件动态地跳过测试用例。`skipif`标记可以接受一个条件表达式和一个跳过的原因,只有当条件表达式为真时,才会跳过对应的测试用例。
import pytest
@pytest.mark.skipif(condition, reason="跳过原因")
def test_example():
# 测试用例的代码
assert 1 + 1 == 2
在上述示例中,`condition`是一个条件表达式,当它为真时,对应的测试用例将被跳过,并且会提供一个跳过的原因。
8、运行不同层级的测试用例
pytest可以运行不同层级的测试用例,从整个文件夹到具体的函数级别。
1. 运行测试文件夹中的所有用例:
pytest <folder_path>
使用上面的命令,pytest将会运行指定文件夹路径下的所有测试用例文件。
2. 运行py文件的所有用例:
pytest <file_path>
使用上面的命令,pytest将会运行指定的.py文件中的所有测试用例。
3. 运行类中的所有用例:
pytest <file_path>::<class_name>
使用上面的命令,pytest将会运行指定.py文件中指定类名的所有测试用例。
4. 运行指定函数的测试用例:
pytest <file_path>::<class_name>::<function_name>
使用上面的命令,pytest将会运行指定.py文件中指定类中指定函数的测试用例。
9、管理测试用例执行顺序
pytest运行测试用例默认执行顺序是,文件之间按ASCLL码排序,文件里的测试用例从上往下执行。
1、使用钩子函数管理测试用例执行顺序:
# 管理收集到的测试用例执行顺序
def pytest_collection_modifyitems(session, config,items):
"""
called after collection is completed.
you can modify the ``items`` list
:param _pytest.main.Session session: the pytest session object
:param _pytest.config.Config config: pytest config object
:param List[_pytest.nodes.Item] items: list of item objects
"""
print("收集到的测试用例:%s"%items)
print("收集到的测试用例items:",type(items))
items.sort(key=lambda x: x.name)
print('调整后的测试用例执行顺序',items)
2、使用 pytest-ordering 插件管理测试用例执行顺序:
注意:这个pytest插件已经不再维护了,只适用于python 3.6之前的版本。
官方文档:pytest-ordering: run your tests in order — pytest-ordering 0.4 documentation
3、使用 pytest-order插件管理测试用例执行顺序:
注意:
pytest-order 是 pytest-ordering 的升级版本。
适用于 Python 3.6 - 3.10;
对于除 Python 3.10 之外的所有版本,pytest 版本 >= 5.0.0;
对于 Python 3.10,pytest >= 6.2.4。
官网文档:pytest-order - a plugin to order test execution — pytest-order 1.0.1 documentation