百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

人生苦短,要会Python!先从搞懂pytest测试框架开始

ccwgpt 2024-11-02 11:02 35 浏览 0 评论

Pytest是成熟的功能齐全的Python测试工具,有助于编写更好的程序。

一、Pytest基本知识

参考官方文档翻译过来,了解一下Pytest知识点。

1、Pytest中可以按节点ID运行测试。

在命令行中指定测试方法的另一个示例:

pytest test_mod.py::TestClass::test_method

2、通过标记表达式运行测试

pytest -m slow

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

3、详细的总结报告

pytest –ra

4、分析测试执行持续时间

要获取最慢的10个测试持续时间的列表,请执行以下操作:

pytest --durations=10

5、将测试报告发送到在线pastebin服务

为每个测试失败创建一个URL:

pytest --pastebin=failed

为整个测试会话日志创建一个URL

pytest --pastebin=all

6、从python代码中调用Pytest

pytest.main()

注意:

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

7、断言

使用标准python assert来验证python测试中的期望和值。

8、conftest.py

对于可能的值scope有:function,class,module,package或session。

9、Pytest将建立一个字符串,它是用于在参数化fixture,例如每个fixtures测试ID。这些ID可以用于-k选择要运行的特定情况,并且当一个故障发生时,它们还将标识特定情况。使用Pytest运行--collect-only将显示生成的ID。

10、使用直接测试参数化fixture

给定测试文件的结构为:

tests/

__init__.py

conftest.py

# content of tests/conftest.py

import pytest

@pytest.fixture

def username():

return 'username'

@pytest.fixture

def other_username(username):

return 'other-' + username

test_something.py

# content of tests/test_something.py

import pytest

@pytest.mark.parametrize('username', ['directly-overridden-username'])

def test_username(username):

assert username == 'directly-overridden-username'

@pytest.mark.parametrize('username', ['directly-overridden-username-other'])

def test_username_other(other_username):

assert other_username == 'other-directly-overridden-username-other'

11、使用非参数化的参数覆盖参数化fixture

给定测试文件的结构为:

tests/

__init__.py

conftest.py

# content of tests/conftest.py

import pytest

@pytest.fixture(params=['one', 'two', 'three'])

def parametrized_username(request):

return request.param

@pytest.fixture

def non_parametrized_username(request):

return 'username'

test_something.py

# content of tests/test_something.py

import pytest

@pytest.fixture

def parametrized_username():

return 'overridden-username'

@pytest.fixture(params=['one', 'two', 'three'])

def non_parametrized_username(request):

return request.param

def test_username(parametrized_username):

assert parametrized_username == 'overridden-username'

def test_parametrized_username(non_parametrized_username):

assert non_parametrized_username in ['one', 'two', 'three']

test_something_else.py

# content of tests/test_something_else.py

def test_username(parametrized_username):

assert parametrized_username in ['one', 'two', 'three']

def test_username(non_parametrized_username):

assert non_parametrized_username == 'username'

12、monkeypatch

简单的api获取例子

# contents of app.py, a simple API retrieval example

import requests

def get_json(url):

"""Takes a URL, and returns the JSON."""

r = requests.get(url)

return r.json()

此外,如果该模拟程序旨在应用于所有测试,则fixture可以将其移动到conftest.py文件中并使用with?autouse=True选项。

13、设置捕获方法或禁用捕获

有两种pytest执行捕获的方法:

  • 文件描述符(FD)级别捕获(默认):将捕获对操作系统文件描述符1和2的所有写操作。
  • sys级别捕获:仅写入Python文件,sys.stdout?并且sys.stderr将被捕获。不捕获对文件描述符的写入。

您可以从命令行影响输出捕获机制:

pytest -s # disable all capturing

pytest --capture=sys # replace sys.stdout/stderr with in-mem files

pytest --capture=fd # also point filedescriptors 1 and 2 to temp file

14、内部Pytest警告

(1)类PytestWarning

基类:UserWarning。

Pytest发出的所有警告的基类。

(2)类PytestAssertRewriteWarning

基类:PytestWarning。

Pytest断言重写模块发出的警告。

(3)类PytestCacheWarning

基地:PytestWarning。

缓存插件在各种情况下发出的警告。

(4)类PytestCollectionWarning

基类:PytestWarning。

Pytest无法在模块中收集文件或符号时发出警告。

(5)类PytestConfigWarning

基地:PytestWarning。

针对配置问题发出警告。

(6)类PytestDeprecationWarning

基类:Pytest.PytestWarning,DeprecationWarning。

在将来的版本中将删除的功能的警告类。

(7)类PytestExperimentalApiWarning

基类:Pytest.PytestWarning,FutureWarning。

警告类别,用于表示Pytest中的实验。请谨慎使用,因为API可能会更改,甚至在将来的版本中会完全删除。

(8)类PytestUnhandledCoroutineWarning

基类:PytestWarning。

当Pytest遇到作为协程的测试函数时发出警告,但任何异步感知插件均未处理该警告。本机不支持协程测试功能。

(9)类PytestUnknownMarkWarning

基类:PytestWarning。

使用未知标记会发出警告。

1)doctest

就像普通的一样conftest.py,fixtures是在目录树conftest中发现的。这意味着,如果将doctest与源代码一起放入,则相关的conftest.py需要位于同一目录树中。fixtures不会在同级目录树中发现!

2)跳过和xfail

一个xfail意味着你期望测试失败的某些原因。一个常见的示例是对尚未实现的功能或尚未修复的错误进行测试。如果尽管测试通过但预期会失败(标记为pytest.mark.xfail),则为xpass,并将在测试摘要中报告。

Pytest分别统计和列出跳过和xfail测试。默认情况下,不显示有关跳过/未通过测试的详细信息,以避免混乱输出。

pytest -rxXs # show extra info on xfailed, xpassed, and skipped tests

17、如何在不同情况下跳过模块中的测试的快速指南:

1)无条件跳过模块中的所有测试:

pytestmark = pytest.mark.skip("all tests still WIP")

2)根据某些条件跳过模块中的所有测试:

pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="tests for linux only")

3)如果缺少某些导入,请跳过模块中的所有测试:

pexpect = pytest.importorskip("pexpect")

18、跨测试运行

该插件提供了两个命令行选项,以从上次Pytest调用重新运行失败:

  • --lf,--last-failed-仅重新运行失败。
  • --ff,--failed-first-先运行故障,然后测试的其余部分

最后一次运行没有测试失败,或者找不到缓存的lastfailed数据,

Pytest则可以使用以下--last-failed-no-failures选项之一将该选项配置为运行所有测试或不运行测试:

pytest --last-failed --last-failed-no-failures all # run all tests (default behavior)

pytest --last-failed --last-failed-no-failures none # run no tests and exit

19、Pytest支持unittest开箱即用地运行基于Python 的测试

到目前为止,Pytest不支持以下功能:

  • load_tests协议 ;
  • 子测试

1)具有在给定上下文中自动使用的fixture,@pytest.fixture(autouse=True)

2)xunit样式: 在每个模块/类/功能的基础上实现fixture

Module setup/teardown

def setup_module(module):

""" setup any state specific to the execution of the given module."""

def teardown_module(module):

""" teardown any state that was previously setup with a setup_module

method.

"""

Class setup/teardown

@classmethod

def setup_class(cls):

""" setup any state specific to the execution of the given class (which

usually contains tests).

"""

@classmethod

def teardown_class(cls):

""" teardown any state that was previously setup with a call to

setup_class.

"""

方法和功能的setup/teardown

def setup_method(self,method):

""" setup any state tied to the execution of the given method in a

class. setup_method is invoked for every test method of a class.

"""

def teardown_method(self,method):

""" teardown any state that was previously setup with a setup_method

call.

"""

def setup_function(function):

""" setup any state tied to the execution of the given function.

Invoked for every test function in the module.

"""

def teardown_function(function):

""" teardown any state that was previously setup with a setup_function call.

"""

3)工具启动时插件发现顺序

通常最好将conftest.py文件保存在顶级测试或项目根目录中。

20、典型setup.py摘录:

setup(..., entry_points={"pytest11": ["foo = pytest_foo.plugin"]}, ...)

21、通过名字来访问另一个插件

插件想要与另一个插件的代码协作,则可以通过插件管理器获取引用

plugin = config.pluginmanager.get_plugin("name_of_plugin")

22、Pytest API

23、caplog()

访问和控制日志捕获。

捕获的日志可通过以下属性/方法获得:

* caplog.messages -> list of format-interpolated log messages

* caplog.text -> string containing formatted log output

* caplog.records -> list of logging.LogRecord instances

* caplog.record_tuples -> list of (logger_name, level, message) tuples

* caplog.clear() -> clear captured records and formatted log output string

24、pip用于安装应用程序和所有依赖项以及Pytest程序包本身。这样可确保您的代码和依赖项与系统Python安装隔离。

25、Pytest.approx

26、失败的视频/屏幕截图Pytest-splinter、Pytest-bdd

27. 考虑以下文件和目录布局:

root/

|- foo/

|- __init__.py

|- conftest.py

|- bar/

|- __init__.py

|- tests/

|- __init__.py

|- test_foo.py

执行时会执行以下所有的目录文件

pytest root/

28、测试模块名称不能相同

29、从中找到rootdir的算法args:

  • 确定指定的公共祖先目录,这些目录args被识别为文件系统中存在的路径。如果找不到此类路径,则将公共祖先目录设置为当前工作目录。
  • 寻找Pytest.ini,tox.ini并setup.cfg在父目录和文件向上。如果匹配,它将成为ini文件,并且其目录将成为rootdir。
  • 如果未找到ini文件,请setup.py从公共祖先目录向上查找以确定rootdir。
  • 如果没有setup.py被发现,寻找Pytest.ini,tox.ini并?setup.cfg在每个指定args向上。如果匹配,它将成为ini文件,并且其目录将成为rootdir。
  • 如果找不到ini文件,则使用已经确定的公共祖先作为根目录。这允许在不属于包且没有任何特定ini文件配置的结构中使用Pytest。

二、Pytest 实际运用

命令行中执行

pip install pytest

pip show pytest

想要在 Pycharm 环境中测试用例以 Pytest 形式运行,可以这样设置。

Settings->Tools->Python Integreated Tools,选择默认的 test runner 为“py.test”。

Pytest 生成 html 报告,命令行中安装 Pytest-html 插件。

pip install pytest-html

cmd 中执行 >pytest test_***.py --html=./testreport.html

在报告存放路径下,可以用 Chrome 浏览器打开本地 html 链接,如

file:///E:/ATS/Test_doctor/testreport.html。

Pytest 测试报告形式如下所示

Pytest 失败重跑机制。在 UI 自动化测试中,由于受到网络不稳定、appium server 等影响,不是每次正确的测试用例都能运行通过,于是使用 Pytest 的失败重跑提高自动化测试的稳定性。安装插件 Pytest-rerunsfailures,在命令行执行

pip install pytest-rerunsfailures

>pytest test_patlist.py --reruns 3 --html=./report.html

实现对测试用例重跑 3 次,3 次不通过才算失败,反之则运行成功。

实践得到,Pytest 不需要创建类,直接定义函数即可。

Pytest 和 unittest 最大的区别是不要求我们必须创建测试类, 自己创建的测试类也不需要继承于 unittest.TestCase 类。但是 Pytest 要求我们创建的测试文件,测试类、方法、测试函数必须以“test”开头,Pytest 默认按照这个规则查找测试用例并执行它们。”

三、Pytest 避开的坑

1)PytestUnknownMarkWarning

解决方案:

① 若是单个标签

在 conftest.py 添加如下代码,直接拷贝过去,把标签名改成你自己的就行了

def pytest_configure(config):

config.addinivalue_line(

"markers", "login_success" # login_success 是标签名

)

② 若是多个标签

在 conftest.py 添加如下代码,直接拷贝过去,把标签名改成你自己的就行了

def pytest_configure(config):

marker_list = ["testmark1","testmark2","testmark3"] # 标签名集合

for markers in marker_list:

config.addinivalue_line(

"markers", markers

)

这样添加之后,再次运行,不再出现 warning。

2)UnicodeDecodeError: 'gbk' codec can't decode byte 0xae in position 42: illegal multibyte sequence

import pytest

@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+4",6),("6*9",42)])

def test_eval(test_input,expected):

assert eval(test_input) == expected

解决办法:这个跟编码有关,代码目录中有个 Pytest.ini 文件,内容是这样:

[pytest]

doctest_encoding = UTF-8 #默认编码是 UTF-8

删除 Pytest.ini 文件之后,再次运行就可以了。

3)Pytest 执行用例时 collected 0 items

Pytest 执行的文件需要以 test 开头才能被查找到。

4)断言 assert

断言元素是否存在,例如

element = appdriver.find_element_by_id('icon_id')

assert element

我是谁?


我是一名从事了多年软件测试的老测试员,今年年初我花了一个月整理了一份最适合2020年学习的软件测试学习干货,可以送给每一位对软件测试感兴趣的小伙伴,想要获取的可以关注我的头条号并在后台私信我:【测试】,即可免费获取。

相关推荐

用Deepseek扩写土木工程毕业论文实操指南

用Deepseek扩写毕业论文实操指南一、前期准备整理现有论文初稿/提纲列清楚论文核心框架(背景、现状、意义、方法、数据、结论等)梳理好关键文献,明确核心技术路线二、Deepseek扩写核心思路...

985学霸亲授,DeepSeek也能绘6大科研图表,5分钟就出图

在实验数据处理中,高效可视化是每个科研人的必修课。传统绘图软件操作复杂、耗时费力,而智能工具DeepSeek的出现彻底改变了这一现状。本文将详解如何用DeepSeek一键生成六大科研常用图表,从思维导...

AI写论文刷屏?大学生正在丢掉的思考力

一、宿舍深夜:当论文变成"Ctrl+C+V"凌晨两点的大学宿舍,小王对着电脑屏幕叹气。本该三天前开始写的近代史论文,此刻还一片空白。他熟练打开某AI写作网站,输入"论五四运动的...

Grok在辅助论文写作上能不能既“聪明”又“可怕”?!

AcademicIdeas-学境思源AI初稿写作随着人工智能技术的飞速发展,论文写作这一学术任务正迎来新的助力。2025年2月18日,美国xAI公司推出了备受瞩目的Grok3模型,其创始人埃隆·...

大四论文沟通场景!音频转文字难题听脑AI来化解

大四学生都知道,写论文时和导师沟通修改意见,简直是“过关斩将”。电话、语音沟通完,想把导师说的修改方向、重点要求记下来,麻烦事儿可不少。手写记不全,用普通录音转文字工具,转完还得自己慢慢找重点,稍不注...

论文写作 | 技术路线图怎么画?(提供经典优秀模板参考)

技术路线图是一种图表或文字说明,用于描述研究目标、方法和实施计划。它展示了研究的整体框架和步骤,有助于读者理解研究的逻辑和进展。在课题及论文中,技术路线图是常见的一部分,甚至是一个类似心脏一样的中枢器...

25年信息系统项目管理师考试第2批论文题目写作建议思路框架

25年信息系统项目管理师考试第2批论文题目写作建议思路框架--马军老师

微信购物应尽快纳入法律框架(微信购物管辖)

符向军近日,甘肃省工商行政管理局发布《2016年上半年信息分析报告》。报告显示,微信网购纠纷迅猛增长,网络购物投诉呈上升趋势。投诉的主要问题有出售的商品质量不过关、消费者通过微信付款后对方不发货、购买...

泛珠三角区域网络媒体与腾讯微信签署《战略合作框架协议》

新海南客户端、南海网7月14日消息(记者任桐)7月14日上午,参加第四届泛珠三角区域合作网络媒体论坛的区域网络媒体负责人及嘉宾一行到腾讯微信总部座谈交流,并签署《战略合作框架协议》(以下简称《框架协...

离线使用、植入微信-看乐心Mambo手环如何打破框架

从2014年开始智能手环就成功进入人们的生活,至今已经演变出数据监测、信息推送、心率监测等诸多五花八门的功能,人们选择智能手环并不指望其能够改变身体健康情况,更多的是通过数据来正视自身运动情况和身体健...

微信私域电商运营策略与框架(微信私域怎么做)

...

华专网络:如何零基础制作一个网站出来?

#如何零基础制作一个网站出来?#你是不是觉得网站建设很复杂,觉得自己是小白,需求不明确、流程搞不懂、怕被外包公司坑……这些问题我都懂!今天华专网络就用大白话给你捋清楚建站的全流程,让你轻松get网站制...

WAIC2024丨明日上午9点,不见不散!共同探讨智能社会与全球治理框架

大咖云集,硕果闪耀WAIC2024世界人工智能大会智能社会论坛将于7月5日9:00-12:00与你相约直播间WAIC2024上海杨浦同济大学哔哩哔哩多平台同步直播探讨智能社会与全球治理框架WAIC...

约基奇:森林狼换来戈贝尔时大家都在嘲笑 他们的阵容框架很不错

直播吧5月4日讯西部季后赛半决赛,掘金将迎战森林狼,约基奇赛前接受采访。约基奇说道:“当蒂姆-康纳利(森林狼总经理、前掘金总经理&曾选中约基奇)做了那笔交易(换来戈贝尔)时,每个人都在嘲笑他...

视频号带货为什么一个流量都没有?顶级分析框架送给你

视频号带货为什么一个流量都没有?遇到问题,一定是步步来分析内容,视频号带货一个流量都没有,用另外一个意思来讲,就可以说是零播放。为什么视频号带货一个流量都没有?跟你说再多,都不如来个分析框架。1、是否...

取消回复欢迎 发表评论: