文章目录

  • PyTest
    • 一、 快速开始
      • 1、 介绍
      • 2、 安装
      • 3、 第一个测试
      • 4、 断言引发异常
      • 5、 分组测试
      • 6、 添加临时目录
    • 二、 调用测试
      • 1、 布局规则
        • 1.1 规则
        • 1.2 测试布局
          • 1.2.1 测试代码分离
          • 1.2.2 测试代码结合
      • 2、 运行测试
        • 2.1 命令行调用
        • 2.2 代码中调用
    • 三、 使用方法
      • 1、 断言
        • 1.1 assert
        • 1.2 异常断言
      • 2、 固定装置
        • 2.1 简单使用
        • 2.2 共享数据
      • 3、 标记测试
        • 3.1 标记
        • 3.2 节点
        • 3.2 名称

PyTest

一、 快速开始

1、 介绍

pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:

  • 简单灵活,容易上手
  • 支持参数化
  • 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)
  • pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
  • 测试用例的skip和xfail处理
  • 可以很好的和jenkins集成
  • report框架----allure 也支持了pytest

官方文档位置:https://docs.pytest.org/en/7.1.x/

2、 安装

这里使用的是poetry来进行安装的,poetry使用方法

poetry add pytest  # 添加pytest
poetry add pytest-html  # 添加 html 测试报告生成
pytest --version  # 检测是否安装成功

3、 第一个测试

创建一个test_*.py或者*_test..py的文件,运行的时候,pytest可以自动检测这些测试文件:

# content of test_sample.py
def func(x):return x + 1def test_answer():assert func(3) == 5

你可以使用 assert 验证测试期望的声明。皮特试验 Advanced assertion introspection 将智能地报告断言表达式的中间值,以便避免使用多个名称 of JUnit legacy methods .

然后,我们就使用,pytest提供的命令开始进行测试:

pytest tests --html report.html  # --html 指定html输出的位置,tests是存放测试文件的文件夹

pytest 将运行窗体测试的所有文件_ *.py or * _当前目录及其子目录中的test.py

运行结果:

4、 断言引发异常

我们使用 raises 助手来断言某些代码引发异常:

# content of test_sysexit.py
import pytestdef f():raise SystemExit(1)def test_mytest():with pytest.raises(SystemExit):f()# 运行测试
# pytest -q

以“安静”报告模式执行测试功能: 它不会显示其为程序的异常,测试正常通过。

pytest中的-q参数代表保持输出简短 ,只输出程序异常的日志,其余的不输出。

5、 分组测试

一旦开发了多个测试,您可能需要将它们分组到一个类中。pytest使创建包含多个测试的类变得很容易:

# content of test_class.py
class TestClass:def test_one(self):x = "this"assert "h" in xdef test_two(self):x = "hello"assert hasattr(x, "check")

pytest 发现以下所有测试 Conventions for Python test discovery ,所以它发现 test_ 前缀函数。没有必要对任何东西进行子类化,但是要确保在类前面加上 Test 否则将跳过该类。我们只需传递其文件名即可运行该模块:

pytest -q test_class.py

第一次测试通过,第二次失败。您可以很容易地看到断言中的中间值,以帮助您理解失败的原因。

将测试分组在类中是有益的,原因如下:

  • 试验机构
  • 仅在该特定类中共享测试夹具
  • 在类级别应用标记并将其隐式应用于所有测试

在类中对测试分组时需要注意的是,每个测试都有一个唯一的类实例。让每个测试共享同一个类实例将非常不利于测试隔离,并且会导致不良的测试实践。概述如下:

# content of test_class_demo.py
class TestClassDemoInstance:value = 0def test_one(self):self.value = 1  # 只有静态函数才可以修改类属性,这里是修改失败的assert self.value == 1def test_two(self):assert self.value == 1
pytest -k TestClassDemoInstance -q
  • 在类级别添加的属性是类属性,因此它们将在测试之间共享

6、 添加临时目录

pytest提供内置固定装置/函数参数来请求任意资源,例如唯一的临时目录:

# content of test_tmp_path.py
def test_needsfiles(tmp_path):print(tmp_path)assert 0
# pytest -q test_tmp_path.py # 运行

列出名字 tmpdir 在测试函数签名和 pytest 将在执行测试函数调用之前查找并调用fixture工厂以创建资源。

使用pytest --fixtures命令查看有哪些ficture工厂。

二、 调用测试

1、 布局规则

这里使用的是poetry进行快速生成目录结构的,poetry使用方法。

1.1 规则

pytest实现以下标准测试发现:

  • 如果未指定参数,则收集从testpaths (如果已配置)或当前目录开始。或者,命令行参数可用于目录、文件名或节点 ID 的任意组合。
  • 递归到目录,除非它们匹配norecursedirs
  • 在这些目录中,搜索test_*.py或文件,由它们的测试包名称*_test.py导入。
  • 从这些文件中,收集测试项目:
    • test类外的前缀测试函数或方法
    • test前缀测试类中的前缀测试函数或方法Test(没有__init__方法)

在 Python 模块中,pytest还使用标准 unittest.TestCase子类化技术发现测试。

1.2 测试布局

1.2.1 测试代码分离

如果您有许多功能测试或出于其他原因希望将测试与实际应用程序代码分开(通常是一个好主意),则将测试放入实际应用程序代码之外的额外目录可能会很有用:

pyproject.toml
src/mypkg/__init__.pyapp.pyview.py
tests/test_app.pytest_view.py...

快速生成的方法:

poetry new --src mypkg

运行测试的方法:

pytest python -m pytest

通常,但特别是如果您使用默认导入模式prepend强烈建议使用src布局。在这里,您的应用程序根包位于根目录的子目录中,src/mypkg/而不是mypkg

1.2.2 测试代码结合

如果您在测试和应用程序模块之间有直接关系并且希望将它们与您的应用程序一起分发,则将测试目录内联到您的应用程序包中很有用:

pyproject.toml
[src/]mypkg/__init__.pyapp.pyview.pytest/__init__.pytest_app.pytest_view.py...

运行方法:

pytest --pyargs mypkg

pytest将发现mypkg安装位置并从那里收集测试,这样可以很轻松的运行测试代码。

2、 运行测试

2.1 命令行调用

Pytest 支持多种从命令行运行和选择测试的方法。

# 在模块中运行测试
pytest test_mod.py# 在目录中运行测试
pytest testing/# 通过关键字表达式运行测试
pytest -k "MyClass and not method"

第三种方式:

  • 这将运行包含与给定字符串表达式匹配的名称(不区分大小写)的测试,其中可以包括使用文件名、类名和函数名作为变量的 Python 运算符。上面的例子会运行TestMyClass.test_something ,但不会TestMyClass.test_method_simple

按节点 ID 运行测试

每个收集到的测试都被分配一个唯一的nodeid,它由模块文件名和后面的说明符组成,如类名、函数名和参数化的参数,用::字符分隔。

# 要在模块中运行特定测试:
pytest test_mod.py::test_func# 在命令行中指定测试方法的另一个示例:
pytest test_mod.py::TestClass::test_method

通过标记运行实例

pytest -m slow

将运行所有用@pytest.mark.slow装饰器装饰的测试。

从包运行测试

pytest --pyargs pkg.testing

这将导入pkg.testing并使用其文件系统位置来查找和运行测试。

获取版本信息等等

pytest --version   # shows where pytest was imported from
pytest --fixtures  # show available builtin function arguments
pytest -h | --help # show help on command line and config file options

分析测试执行持续时间

要获得超过 1.0 秒的最慢 10 个测试持续时间的列表

pytest --durations=10 --durations-min=1.0

通过python解释器调用测试

python -m pytest [...]  # 后面传递的参数和上面的类似

2.2 代码中调用

pytest您可以直接从 Python 代码调用:

retcode = pytest.main()

这就像您从命令行调用“pytest”一样。它不会引发SystemExit而是返回退出代码。您可以传入选项和参数:

retcode = pytest.main(["-x", "mytestdir"])

导入其他插件:

# content of myinvoke.py
import pytest
import sysclass MyPlugin:def pytest_sessionfinish(self):print("*** test run reporting finishing")if __name__ == "__main__":sys.exit(pytest.main(["-qq"], plugins=[MyPlugin()]))

调用pytest.main()将导致导入您的测试和它们导入的任何模块。由于 python 导入系统的缓存机制,pytest.main()从同一进程进行后续调用不会反映调用之间对这些文件的更改。因此,pytest.main()不建议从同一进程多次调用(例如,为了重新运行测试)。

三、 使用方法

1、 断言

1.1 assert

pytest允许您使用标准 Pythonassert来验证 Python 测试中的期望值和值。例如,您可以编写以下内容:

# content of test_assert1.py
def f():return 3def test_function():"""如果失败,可以查看函数的返回值"""assert f() == 4assert a % 2 == 0, "value was odd, should be even"  # 指定自定义的异常断言信息

1.2 异常断言

为了编写有关引发异常的断言,您可以 pytest.raises()像这样使用上下文管理器:

def test_recursion_depth():with pytest.raises(RuntimeError) as excinfo:def f():f()f()assert "maximum recursion" in str(excinfo.value)  # excinfo保存着异常信息

excinfo是一个ExceptionInfo实例,它是引发的实际异常的包装器。感兴趣的主要属性 .type.value.traceback

您可以将match关键字参数传递给上下文管理器,以测试正则表达式是否匹配异常的字符串表示形式(类似于TestCase.assertRaisesRegex方法 from unittest):

import pytestdef myfunc():raise ValueError("Exception 123 raised")def test_match():with pytest.raises(ValueError, match=r".* 123 .*"):myfunc()

也可以为pytest.mark.xfail指定一个“raises”参数 ,它以一种更具体的方式检查测试是否失败,而不仅仅是引发任何异常:

@pytest.mark.xfail(raises=IndexError)
def test_f():f()

pytest.raises()对于您正在测试自己的代码故意引发的异常的情况, 使用可能会更好,而使用@pytest.mark.xfail检查功能可能更适合记录未修复的错误(测试描述“应该”发生什么)或依赖项中的错误

2、 固定装置

2.1 简单使用

在基本层面上,测试函数通过将它们声明为参数来请求它们所需的fixtures

当 pytest 开始运行测试时,它会查看该测试函数签名中的参数,然后搜索与这些参数具有相同名称的fixtures。一旦 pytest 找到它们,它就会运行这些固定装置,捕获它们返回的内容(如果有的话),并将这些对象作为参数传递给测试函数。

import pytestclass Fruit:def __init__(self, name):self.name = nameself.cubed = Falsedef cube(self):self.cubed = Trueclass FruitSalad:def __init__(self, *fruit_bowl):self.fruit = fruit_bowlself._cube_fruit()def _cube_fruit(self):for fruit in self.fruit:fruit.cube()# Arrange
@pytest.fixture
def fruit_bowl():return [Fruit("apple"), Fruit("banana")]def test_fruit_salad(fruit_bowl):# Actfruit_salad = FruitSalad(*fruit_bowl)# Assertassert all(fruit.cubed for fruit in fruit_salad.fruit)

在这个例子中,test_fruit_salad需要 fruit_bowl作为依赖,当 pytest 看到这个时,它将执行夹具函数并将它返回的对象 作为参数传递。

注意:

  1. 固定装置可以嵌套调用

    # contents of test_append.py
    import pytest# Arrange
    @pytest.fixture
    def first_entry():return "a"# Arrange
    @pytest.fixture
    def order(first_entry):return [first_entry]def test_string(order):# Actorder.append("b")# Assertassert order == ["a", "b"]
    
  2. 一个测试函数或者固定装置可以使用多个固定装置

    # contents of test_append.py
    import pytest# Arrange
    @pytest.fixture
    def first_entry():return "a"# Arrange
    @pytest.fixture
    def second_entry():return 2# Arrange
    @pytest.fixture
    def order(first_entry, second_entry):return [first_entry, second_entry]# Arrange
    @pytest.fixture
    def expected_list():return ["a", 2, 3.0]def test_string(order, expected_list):# Actorder.append(3.0)# Assertassert order == expected_list
    
  3. 固定装置可以重复使用

    # contents of test_append.py
    import pytest# Arrange
    @pytest.fixture
    def first_entry():return "a"# Arrange
    @pytest.fixture
    def order(first_entry):return [first_entry]def test_string(order):# Actorder.append("b")# Assertassert order == ["a", "b"]def test_int(order):# Actorder.append(2)# Assertassert order == ["a", 2]
    

    在同一个测试期间,也可以多次请求夹具,并且 pytest 不会为该测试再次执行它们。这意味着我们可以在依赖于它们的多个固定装置中请求 固定装置(甚至在测试本身中再次请求固定装置),而无需多次执行这些固定装置。

  4. 自动使用固定装置

    # contents of test_append.py
    import pytest@pytest.fixture
    def first_entry():return "a"@pytest.fixture
    def order(first_entry):return []@pytest.fixture(autouse=True)
    def append_first(order, first_entry):return order.append(first_entry)def test_string_only(order, first_entry):assert order == [first_entry]def test_string_and_int(order, first_entry):order.append(2)assert order == [first_entry, 2]
    

    在此示例中,append_first夹具是自动使用夹具。因为它是自动发生的,所以两个测试都会受到它的影响,即使两个测试都没有 请求它。这并不意味着他们不能被请求;只是没有必要。

2.2 共享数据

需要网络访问的设备取决于连接性,并且通常创建起来很耗时。我们可以scope="module"在调用中添加一个参数来 @pytest.fixture添加一个smtp_connection固定装置,负责创建到一个预先存在的 SMTP 服务器的连接,每个测试模块只调用一次(默认是每个测试函数调用一次)。因此,测试模块中的多个测试函数将接收相同的smtp_connection夹具实例,从而节省时间。scope的可能值为:functionclassmodulepackagesession

下一个示例将fixture函数放入一个单独的conftest.py文件中,以便目录中多个测试模块的测试可以访问fixture函数:

# content of conftest.py
import pytest
import smtplib@pytest.fixture(scope="module")
def smtp_connection():return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)  # 这里也可以使用yield来返回参数,进行后续的内容
# content of test_module.pydef test_ehlo(smtp_connection):response, msg = smtp_connection.ehlo()assert response == 250assert b"smtp.gmail.com" in msgassert 0  # for demo purposesdef test_noop(smtp_connection):response, msg = smtp_connection.noop()assert response == 250assert 0  # for demo purposes

更加详细的使用方式,可以到官网自行查看

3、 标记测试

3.1 标记

# content of test_server.pyimport pytest@pytest.mark.webtest
def test_send_http():pass  # perform some webtest test for your appdef test_something_quick():passdef test_another():passclass TestClass:def test_method(self):pass

然后,您可以将测试运行限制为仅运行标记为的测试webtest

pytest -v -m webtest
pytest -v -m "not webtest"  # 运行除webtest之外的所有测试

3.2 节点

 pytest -v test_server.py::TestClass::test_methodpytest -v test_server.py::TestClass test_server.py::test_send_http

3.2 名称

根据名称选择

您可以使用-k命令行选项来指定一个表达式,该表达式在测试名称上实现子字符串匹配,而不是在提供的标记上实现完全匹配-m。这使得根据名称选择测试变得容易:

pytest -v -k http
pytest -k "not send_http" -v
pytest -k "http or quick" -v

更高级的用法,可以到官方文档中自己学习,https://docs.pytest.org/en/7.1.x/index.html

Python全功能测试框架pytest相关推荐

  1. 「高效程序员的修炼」快速上手python主流测试框架pytest以及单元测试编写

    如果对你有帮助,就点个赞吧~ 本文主要介绍如果编写Python的单元测试,包括如何使用断言,如何考虑测试哪些情况,如何避免外部依赖对测试的影响,如果用数据驱动的方式简化重复测试的编写等等等等 文章目录 ...

  2. python:单元测试框架pytest的一个简单例子

    之前一般做自动化测试用的是unitest框架,发现pytest同样不错,写一个例子感受一下 test_sample.py import cx_Oracle import config from sen ...

  3. 自动化测试框架Pytest(一)——入门

    今天来学习一款Python的自动化框架--pytest 一.单元测试框架 java:junit和testing python:unittest和pytest 单元测试框架主要做什么: 1.测试发现:从 ...

  4. Python编程必不可少的pytest测试框架

    进行编程测试重要的是为了更高效的完成功能的实现. pytest是基于unittest实现的第三方测试框架,比 unittest 更加的简洁.高效,并且可以完美兼容 unittest 的测试代码,无需对 ...

  5. Python测试框架pytest(05)fixture - error和failed、fixture实例化、多个fixture

    Python测试框架pytest系列可以查看下列 Python测试框架pytest(01)简介.安装.快速入门_编程简单学的博客-CSDN博客 Python测试框架pytest(02)PyCharm设 ...

  6. Python测试框架pytest(04)fixture - 测试用例调用fixture、fixture传递测试数据

    Python测试框架pytest系列可以查看下列 Python测试框架pytest(01)简介.安装.快速入门_编程简单学的博客-CSDN博客 Python测试框架pytest(02)PyCharm设 ...

  7. Python测试框架pytest(03)setup和teardown

    Python测试框架pytest系列可以查看下列 Python测试框架pytest(01)简介.安装.快速入门_编程简单学的博客-CSDN博客 ​​​​​​Python测试框架pytest(02)Py ...

  8. pytest测试框架_聊聊 Python 的单元测试框架(三):最火的 pytest

    本文首发于 HelloGitHub 公众号,并发表于 Prodesire 博客. 一.介绍 本篇文章是<聊聊 Python 的单元测试框架>的第三篇,前两篇分别介绍了标准库 unittes ...

  9. python测试用例管理_Python测试框架Pytest的常用插件测试报告

    原标题:Python测试框架Pytest的常用插件测试报告 一.pytest-html 生成 html 测试报告 要求:Python 3.6+ 安装:pip install pytest-html 文 ...

最新文章

  1. 信息理论基础 周炯槃 常迥
  2. R语言中的聚类的使用
  3. 采集Nginx日志的几种方式
  4. 【手写系列】写出我的第一个框架:迷你版Spring MVC
  5. 冒泡排序(Bubble_Sort)
  6. 联想服务器开机自动重启,解决联想电脑开机一半自动重启的方法
  7. Ubuntu14.04下搭建Bochs仿真平台,同时用该平台安装Linux0.11内核
  8. 通信、计算机、电子相关专业技术工作
  9. k8s各类yaml文件
  10. 母版页与用户控件区别(思维导图整理)
  11. <Android开发> Android开发工具- 之-I2C TOOLS工具使用
  12. ITIL 4讲解: 变更管理
  13. 从信息网络安全规则开始之——ISO27001
  14. conan入门(十九):封装第三方开源库cpp_redis示例
  15. ARM base instruction -- orr
  16. java开源规则引擎比较_常用规则引擎比较分析
  17. java基于springboot+vue+elementui的外卖点餐配送系统 含骑手功能
  18. 知识蒸馏 | 知识蒸馏理论篇
  19. java 线程阻止_Java:在特定队列大小后阻止提交的ExecutorService
  20. 怎么查看服务器的gpu信息,linux 查看服务器gpu

热门文章

  1. 从前端角度浅谈如何做好网站的SEO优化
  2. 非常快速的在ubuntu上搭建openvpn!
  3. An unusual vacation
  4. 分享Silverlight/Windows8/WPF/WP7/HTML5一周学习导读(5月21日-5月26日)
  5. 【DP】poj1671
  6. git配置(SSH)
  7. 一文看懂ARM Cortex-M处理器
  8. 用友NCC的期初数量如何在数据库里面查询?
  9. 前端html和css的基本知识
  10. 跨时钟域的亚稳态处理、为什么要打两拍不是打一拍、为什么打两拍能有效?...