简介

pytest是动态编程语言Python专用的测试框架,它具有易于上手、功能强大、可扩展性好、兼容性强、效率高、第三方插件丰富等特点。

功能特征:

  • 完整的文档,包括安装,教程和PDF文档
  • 简单而又详细的断言模式(使用纯assert语句)
  • 自动发现测试模块和功能(以test为标识)
  • 可以运行unittest和nose框架的测试用例
  • 灵活的固件,用于管理小型或参数化的长期测试资源
  • 丰富的插件架构,拥有三百多个外部插件和丰富的社区

编写规则:

  • 测试文件以test_开头(以_test结尾也可以)
  • 测试类以Test开头,并且不能带有 init 方法
  • 测试函数以test_开头
  • 断言使用基本的assert即可

自动发现规则:

如果未指定任何参数,则从testpaths(如果已配置)或当前目录开始收集。
另外,命令行参数可以在目录、文件名或节点ID的任何组合中使用。
在这些目录中,搜索包含 test_*.py 或 *_test.py 的测试文件。
从这些文件中,收集以test前缀的测试方法,或者在Test前缀的测试类(无__init__方法)中的以test前缀的测试方法。

官方文档:https://docs.pytest.org/en/latest/contents.html


安装

打开bash命令行,运行以下命令:

pip install -U pytest

检查是否安装了正确的版本:

$ pytest --version
pytest 6.1.2

示例

创建一个简单的测试函数:

# test_sample.py
# 被测功能
def func(x):
return x + 1 # 测试成功
def test_pass():
assert func(3) == 4 # 测试失败
def test_fail():
assert func(3) == 5

现在开始执行测试功能:

E:\workspace-py\Pytest>pytest
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2
items test_sample.py .F [100%] =============================================================================== FAILURES ================================================================================
_______________________________________________________________________________ test_fail _______________________________________________________________________________ def test_fail():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3) test_sample.py:16: AssertionError
======================================================================== short test summary info ========================================================================
FAILED test_sample.py::test_fail - assert 4 == 5
====================================================================== 1 failed, 1 passed in 0.16s ======================================================================

这里未指定测试用例,pytest将依据自动发现规则检索并执行测试,等同于 pytest ./test_sample.py

  •   pytest 使用 . 标识测试成功(PASSED)
  •   pytest 使用 F 标识测试失败(FAILED)
  •   可以使用 -v 选项,显示测试的详细信息
  •   可以使用 -h 查看 pytest 的所有选项

标记

默认情况下,pytest 会递归查找当前目录下所有以 test 开始或结尾的 Python 脚本,并执行文件内的所有以 test 开始或结束的函数和方法。

1、如果你想定运行测试用例,可以通过 :: 显式标记(文件名:: 类名::方法名)。

E:\workspace-py\Pytest>pytest test_sample.py::test_pass
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 1
item test_sample.py . [100%] =========================================================================== 1 passed in 0.05s ===========================================================================

2、如果你想选择一些测试用例,可以使用 -k 模糊匹配

E:\workspace-py\Pytest>pytest -k pass test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2 items / 1 deselected / 1 selected test_sample.py . [100%] ==================================================================== 1 passed, 1 deselected in 0.02s ====================================================================

3、如果你想跳过个别测试用例,可以使用 pytest.mark.skip(),或者 pytest.mark.skipif(条件表达式)。

# 测试失败
@pytest.mark.skip()
def test_fail():
assert func(3) == 5
E:\workspace-py\Pytest>pytest -v test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0 -- c:\python37\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.7.3', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'pytest': '6.0.2', 'py': '1.9.0', 'pluggy': '0.13.0'}, 'Plugins': {'allure-pytest': '2.8.
18', 'cov': '2.10.1', 'html': '2.1.1', 'metadata': '1.8.0', 'rerunfailures': '9.1', 'xdist': '2.1.0'}}
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2 items test_sample.py::test_pass PASSED [ 50%]
test_sample.py::test_fail SKIPPED [100%] ===================================================================== 1 passed, 1 skipped in 0.07s ======================================================================

4、如果你想捕捉一些异常,可以使用pytest.raises()。

# test_raises.py

def test_raises():
with pytest.raises(TypeError) as e:
connect('localhost', '6379')
exec_msg = e.value.args[0]
assert exec_msg == 'port type must be int'

5、如果你事先知道测试函数会执行失败,但又不想直接跳过,而是希望显示的提示,可以使用pytest.mark.xfail()。

# 测试失败
@pytest.mark.xfail()
def test_fail():
assert func(3) == 5
E:\workspace-py\Pytest>pytest -k fail test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2 items / 1 deselected / 1 selected test_sample.py x [100%] =================================================================== 1 deselected, 1 xfailed in 0.05s ====================================================================

6、如果你想对某个测试点进行多组数据测试,可以使用 pytest.mark.parametrize(argnames, argvalues) 参数化测试,即每组参数都独立执行一次测试。

注意:以往我们可以把这些参数写在测试函数内部进行遍历,但是当某组参数导致断言失败,测试则就终止了。

# 测试成功
@pytest.mark.parametrize('data', [1, 2, 3])
def test_pass(data):
assert func(data) == 4
E:\workspace-py\Pytest>pytest -k pass test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 4 items / 1 deselected / 3 selected test_sample.py FF. [100%] =============================================================================== FAILURES ================================================================================
_____________________________________________________________________________ test_pass[1] ______________________________________________________________________________ data = 1 @pytest.mark.parametrize('data', [1, 2, 3])
def test_pass(data):
> assert func(data) == 4
E assert 2 == 4
E + where 2 = func(1) test_sample.py:11: AssertionError
_____________________________________________________________________________ test_pass[2] ______________________________________________________________________________ data = 2 @pytest.mark.parametrize('data', [1, 2, 3])
def test_pass(data):
> assert func(data) == 4
E assert 3 == 4
E + where 3 = func(2) test_sample.py:11: AssertionError
======================================================================== short test summary info ========================================================================
FAILED test_sample.py::test_pass[1] - assert 2 == 4
FAILED test_sample.py::test_pass[2] - assert 3 == 4
=============================================================== 2 failed, 1 passed, 1 deselected in 0.17s ===============================================================

固件

固件(Fixture)是一些函数,pytest 会在执行测试函数之前(或之后)加载运行它们。

我们可以利用固件做任何事情,其中最常见的可能就是数据库的初始连接和最后关闭操作。

1、Pytest使用pytest.fixture()定义固件,为了在实际工程中可以更大程度上复用,我们更多的是使用文件conftest.py集中管理固件(pytest会自动调用)。

# conftest.py
import pytest @pytest.fixture()
def data():
return 3
# 测试成功
def test_pass(data):
assert func(data) == 4
E:\workspace-py\Pytest>pytest -k pass test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2 items / 1 deselected / 1 selected test_sample.py . [100%] ==================================================================== 1 passed, 1 deselected in 0.05s ====================================================================

2、Pytest 使用 yield 关键词将固件分为两部分,yield 之前的代码属于预处理,会在测试前执行;yield 之后的代码属于后处理,将在测试完成后执行。

# conftest.py
import pytest @pytest.fixture()
def db():
print('opened')
yield
print('closed')
# 测试成功
def test_pass(db):
assert func(3) == 4
E:\workspace-py\Pytest>pytest -s -k pass test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2 items / 1 deselected / 1 selected test_sample.py opened
.closed ==================================================================== 1 passed, 1 deselected in 0.02s ====================================================================

3、为了更精细化控制固件,pytest使用作用域来进行指定固件的使用范围。

在定义固件时,通过 scope 参数声明作用域,可选项有:

  • function: 函数级,每个测试函数都会执行一次固件(默认值);
  • class: 类级别,每个测试类执行一次,所有方法都可以使用;
  • module: 模块级,每个模块执行一次,模块内函数和方法都可使用;
  • session: 会话级,一次测试只执行一次,所有被找到的函数和方法都可用。
# conftest.py
import pytest @pytest.fixture(scope='function', autouse=True)
def func_scope():
pass @pytest.fixture(scope='module', autouse=True)
def mod_scope():
pass @pytest.fixture(scope='session')
def sess_scope():
pass @pytest.fixture(scope='class')
def class_scope():
pass

# 测试成功
  @pytest.mark.usefixtures('sess_scope')
  def test_pass(class_scope):
      assert func(3) == 4

E:\workspace-py\Pytest>pytest --setup-show -k pass test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2 items / 1 deselected / 1 selected test_sample.py
SETUP S sess_scope
SETUP M mod_scope
SETUP C class_scope
SETUP F func_scope
test_sample.py::test_pass (fixtures used: class_scope, func_scope, mod_scope, sess_scope).
TEARDOWN F func_scope
TEARDOWN C class_scope
TEARDOWN M mod_scope
TEARDOWN S sess_scope ==================================================================== 1 passed, 1 deselected in 0.02s ====================================================================

我们可以把固件作为入参,还可以使用@pytest.mark.usefixtures('class_scope'),或者指定autouse参数让固件自动执行。

并且还可以指定params参数来实现固件的参数化,以及指定name参数来修改固件名。

  • 可以使用 -s 选项,显示print打印信息
  • 可以使用 --setuo-show 选项,显示详细的固件信息

4、内置固件

tmpdir & tmpdir_factory:用于临时文件和目录管理,默认会在测试结束时删除。
pytestconfig:用于读取命令行参数和配置文件
capsys:用于捕获 stdout 和 stderr 的内容,并临时关闭系统输出。
monkeypath:用于运行时动态修改类或模块。
recwarn:用于捕获程序中 warnings 产生的警告。

Pytest学习手册:https://learning-pytest.readthedocs.io/zh/latest/index.html

作者:Leozhanggg

出处:https://www.cnblogs.com/leozhanggg/p/14035202.html

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

Pytest自动化测试 - 简易教程的更多相关文章

  1. Pytest自动化测试-简易入门教程(02)

    Pytest框架简介 Pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:1.简单灵活,容易上手,支持参数化2.能够支持简单的单元测试和复杂的功能测试,3.还可以用来做sel ...

  2. Pytest自动化测试-简易入门教程(03)

    今天分享内容的重点,和大家来讲一下我们的测试框架--Pytest 讲到这个框架的话呢,可能有伙伴就会问老师,我在学习自动化测试过程中,我们要去学一些什么东西? 第一个肯定要学会的是一门编程语言,比如说 ...

  3. Pytest自动化测试-简易入门教程(01)

    我们今天主讲的内容,就是测试框架Pytest,讲到这个测试框架对于没有做过Web自动化的伙伴来说,会觉得这个东西是陌生的,那么到底什么是框架呢?什么又是自动化呢?自动化为什么又要用框架呢? 难道我学自 ...

  4. 生活科技两相宜:(一)Win7使用微软SkyDrive网盘简易教程

    今天得写一个Win7使用微软SkyDrive网盘的简易教程,主要是给我老婆看,顺便贴出来给大家共享一下:)    使用微软SkyDrive网盘有两个层次.一个是使用网页版,这个跟使用163或者QQ网盘 ...

  5. JavaScript简易教程(转)

    原文:http://www.cnblogs.com/yanhaijing/p/3685304.html 这是我所知道的最完整最简洁的JavaScript基础教程. 这篇文章带你尽快走进JavaScri ...

  6. Emacs简易教程

    Emacs简易教程阅读: 命令: $emacs 进入之后,输入: C-h t 这里,C-h表示按住[Ctrl]键的同时按h ####### 20090620 *退出: 输入“C-x C-c” *撤销: ...

  7. 文件上传利器SWFUpload入门简易教程

    凡做过网站开发的都应该知道表单file的确鸡肋. Ajax解决了不刷新页面提交表单,但是却没有解决文件上传不刷新页面,当然也有其它技术让不刷新页面而提交文件,该技术主要是利用隐藏的iFrame, 较A ...

  8. 【转】Delphi内嵌ASM简易教程

    Delphi内嵌ASM简易教程 作者:heiying2006-03-19 18:33分类:默认分类标签: 前言 Delphi作为一个快速高效的开发平台,使用的人越来越多,但熟悉在Delphi代码中嵌入 ...

  9. Ant 简易教程

    转载:http://www.cnblogs.com/jingmoxukong/p/4433945.html Ant 简易教程 Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动 ...

随机推荐

  1. ES6里class杂乱随笔

    这是一篇乱七八糟的随笔.class是ES6新增的特性,用于解决JavaScript没有类的困惑. --杂谈 ES5及之前,类都是用函数来替代,包括实例. 如: 1 function Person(na ...

  2. Java9系列第九篇-对HTTP2协议的支持与非阻塞HTTP-API

    在HTTP/1.1 发布了16 年之后,IETF在2015年终于通过了HTTP/2 协议.HTTP/2协议旨在降低延迟,满足当今时代对于信息响应时间的要求.在这篇文章中,我会简要的对HTTP/2协议进 ...

  3. D. Yet Another Problem On a Subsequence 解析(DP)

    Codeforce 1000 D. Yet Another Problem On a Subsequence 解析(DP) 今天我們來看看CF1000D 題目連結 題目 略,請直接看原題 前言 這題提 ...

  4. Java8新特性探索之Lambda表达式

    为什么引入Lambda表达式? Lambda 表达式产生函数,而不是类. 在 JVM(Java Virtual Machine,Java 虚拟机)上,一切都是一个类,因此在幕后执行各种操作使 lamb ...

  5. lora技术在电力行业的应用

    智能电网的目标是建立一个高速通信网络之上的传统电网.它通过传感,分析,预测,决策和控制提供稳定,高效的电力供应.传统电网分为三个主要区域S-发电,输电和配电.先进的计量系统是使这种传统电网智能化的基础 ...

  6. Java 解决Enum.valueOf找不到枚举出现的异常

    由于Enum.valueOf匹配不到枚举时会出现异常,这个可以用try...catch来解决,但是这样会导致代码往臃肿的道路上越走越远. 本文与其说是解决Enum.valueOf找不到枚举出现的异常还 ...

  7. Git的全局及单个仓库配置

    我们先来了解一下在git中的配置文件路径: /etc/gitconfig 文件: 包含系统上每一个用户及他们仓库的通用配置. 如果在执行 git config 时带上 --system 选项,那么它就 ...

  8. 「SHOI2014」三叉神经树

    「SHOI2014」三叉神经树 给你一颗由\(n\)个非叶子结点和\(2n+1\)个叶子结点构成的完全三叉树,每个叶子结点有一个输出:\(0\)或\(1\),每个非叶子结点的输出为自己的叶子结点中较多 ...

  9. 【Kata Daily 190918】Spacify(插空)

    题目: Modify the spacify function so that it returns the given string with spaces insertedbetween each ...

  10. Appium学习之驱动真机运行

    一.Appium工具的简单原理 Appium工具可以分为:客户端(appium-client).服务端(appium-server)和移动设备端(模拟器或者真机).客户端支持多语言,如:python- ...