【python篇】pytest框架(图文详解)
大卫软件测试 2024-10-03 14:05:03 阅读 81
Pytest框架
介绍
1.简介
pytest是纯python编写的自动化测试框架,可以支持python语法编写测试用例,是一个非常成熟的全功能的Python测试框架。
主要有以下几个特点:
简单灵活,容易上手;支持参数化;能够支持简单的单元测试和复杂的功能测试,还可以结合selenium、requests做自动化测试;pytest具有很多第三方插件,并且可以自定义扩展。
安装:<code>pip install pytest
官方文档:https://docs.pytest.org
2.第一个pytest用例
def test_01():
assert 1 == 1
3.pytest命名规范
测试模块:以 test_
开头命名,如:test_login.py
,或以 _test
结尾;
测试类:必须以Test
开头命名,且测试类中不能有 __init__
方法;
测试方法/测试函数:必须以test
开头。
4.常用参数
可以通过pytest -h来查看所有可用参数。pytest的参数有很多,下面是归纳一些常用的参数:
无参数:读取路径下符合条件的所有类、函数、方法全部执行;
-v:打印详细运行日志;
-s:输出调试信息,包括print打印的信息;命令行输入:pytest -s;
-x:运行用例失败立即停止运行
–maxfail
用例失败数达到某个设定的值停止运行
pytest --maxfail=[num]
-m 运行所有@pytest.mark.[标记名] 标记的用例
比如:用例标记 @pytest.mark.high
pytest -m=hign 或者 pytest -m hign。# 表示只执行有此标记hight的case。
pytest -m="hign or smoke" 或者 pytest -m "hign or smoke" # 表示两种标记都执行
–reruns=num:失败用例重跑num次。需要安装 pytest-rerunfailures 插件模块。
-n参数,启用多线程或分布式运行测试用例。需要安装pip install pytest-xdist 插件模块。
命令行输入:pytest -vs -n=2
-k: 指定运行某个或某些用例
pytest -k ‘类名’
pytest -k ‘方法名’
pytest -k ‘类名 and not 方法名’ # 运行类里所有方法,不包含某个方法
命令行输入:pytest -vs -k=01
python程序运行pytest:
caseNameString = " or ".join(caseNameList)
cmd = f"python -m pytest -k \"{caseNameString}\" --alluredir ./allure --clean-alluredir"
os.system(cmd)
-k的值支持中文的哟~
参数-n,启用多线程或分布式运行测试用例。需要安装pip install pytest-xdist 插件模块。
命令行输入:pytest -vs -n=2
5.实现数据驱动
Pytest 测试框架的数据驱动是由 pytest 自带的pytest.mark.parametrize()来实现的。
@pytest.mark.parametrize() 装饰器接收两个参数:
第一个参数以字符串的形式存在,它代表能被测试函数所能接受的参数,如果被测试函数有多个参数,则以逗号分隔;
第二个参数用于保存测试数据。如果只有一组数据,以列表的形式存在,如果有多组数据,以列表嵌套元组的形式存在(例如: [1,1]或者[(1,1), (2,2)])。
实例
<code>class Test01:
@pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
def test_001(self,a,b,expect):
print('测试a+b的结果')
assert a+b==expect
@pytest.mark.parametrize('c,d,expect', [(2, 4, 2), (9, 10, 1)])
def test_002(self,c,d,expect):
assert d-c==expect
if __name__ == '__main__':
pytest.main([__file__, '-k','test_001'])
6.pytest fixtures
6.1 fixture用途
fixture主要用来做初始化环境以及测试结束后的数据清除。pytest fixture与setup,teardown功能一样,但比之更加灵活,完全可以代替setup,teardown。
6.2 fixture参数详解
@pytest.fixture(scope='function',params=None,autouse=False,ids=None,name=None)
yield
fixture装饰器,相当于setup,测试用例的前置
* scope: 有四个级别参数'function(默认)'、'class'、'module'、'session'。
* params:一个可选的参数列表,列表中每个数据都可以作为用例的输入。也就说有多少数据,就会形成多少用例。可以通过request.param来获取该次调用的参数。
* autouse:如果True,自动调用fixture功能。如果为False则需要调用fixture。
* ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成。
* name:fixture的名称。这默认为装饰函数的名称。如果fixture在定义它的统一模块。
yield:这个关键字之后的代码相当于teardown,测试用例的后置。
6.3 fixture的作用范围
fixture里面有个scope参数可以控制fixture的作用范围:session>module>class>function
-function:每一个函数或方法都会调用
-class:每一个类调用一次,一个类中可以有多个方法
-module:每一个.py文件调用一次,该文件内又有多个function和class
-session:是多个文件调用一次,可以跨.py文件调用,每个.py文件就是module
6.4 调用fixture的三种方法
方式1:函数或类里直接传fixture的函数名称
def test_fixture(self):
print('\n用例开始执行fix1\n')
yield
print('\n用例执行结束fix1\n')
def test_a(self, test_fixture):
print('runing')
assert 1 == 1
执行结果:
方式2: 使用装饰器@pytest.mark.usefixtures()修饰需要运行的用例(可以叠加使用多个装饰器)
def test_fixture(self):
print('\n用例开始执行fix1\n')
yield
print('\n用例执行结束fix1\n')
@pytest.fixture()
def test_fixture2(self):
print('\n用例开始执行fix2\n')
yield
print('\n用例执行结束fix2\n')
@pytest.mark.usefixtures('test_fixture')
@pytest.mark.usefixtures('test_fixture2')
def test_b(self):
assert 1==1
执行结果
7.skip – 跳过测试
7.1 pytest.skip() 用于函数内,跳过测试用例
<code>@pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
def test_001(self,test1,a,b,expect):
pytest.skip('跳过此测试用例')
assert a+b==expect
用于函数外,跳过测试用例
@pytest.mark.skip(reason="功能未实现")code>
@pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
def test_001(self,test1,a,b,expect):
assert a+b==expect
用在函数外,条件condition为True时,跳过用例
@pytest.mark.skipif(condition=True,reason="功能未实现")code>
@pytest.mark.parametrize('a,b,expect',[(1,1,1),(2,3,5)])
def test_001(self,test1,a,b,expect):
assert a+b==expect
8.rerunfailure–失败重跑,插件pytest-rerunfailures
安装
前提条件: pytest (>=5.3)
和python >=3.6
安装:pip install pytest-rerunfailures
查看安装版本:pip show pytest-rerunfailures
pytest-rerunfailures 使用
命令行参数: --reruns n(重新运行次数)–reruns-delay m(等待运行秒数)使用装饰器: @pytest.mark.flaky(reruns=5, reruns_delay=2)
命令行实例
#!/usr/bin/env python3
# !coding:utf-8
import pytest
import random
def test_simple_assume():
# 每次case运行的值为1或者2,具有随机性
r = random.randint(1, 3)
assert r == 1
if __name__ == '__main__':
pytest.main(['Test_demo01.py', '-v', '--reruns=2', '--reruns-delay 2'])
配置执行次数越多(如--reruns=2),执行的成功率越高。
命令行参数:
--reruns n
(重新运行次数),--reruns-delay m
(等待运行秒数)
例如
pytest pytest-demo.py --reruns 3 --reruns-delay 2
装饰器实例
@pytest.mark.flaky(reruns=5, reruns_delay=2)
def test_01(self):
print('---用例01---')
assert 1 == 2
执行结果
9.Mark装饰器之order执行顺序
需要先安装插件
cmd命令窗口:pip install pytest-ordering
在pycharm中File-->settings-->Project-->Python Interpreter-->点击+号-->搜索pytest-ordering安装。
查看安装版本:pip show pytest-ordering
使用方法:
控制用例执行顺序的方法;在需要调整用例执行顺序的函数(或方法)前增加,如@pytest.mark.run(order=x),x表示数字;执行顺序,由小到大、由正到负、未标记的在正数后、负数前执行,顺序为:1,2,3,无标记,-3,-2,-1;
实例
<code>import pytest
class Test_Class3():
@pytest.mark.run(order=2)
def test_case1(self):
print("测试方法1")
@pytest.mark.run(order=1)
def test_case2(self):
print("测试方法2")
@pytest.mark.run(order=3)
def test_case3(self):
print("测试方法3")
if __name__ == '__main__':
pytest.main(['Test_demo02.py' '-s'])
执行结果
============================= test session starts =============================
collecting ... collected 3 items
Test_demo02.py::Test_Class3::test_case2 PASSED [ 33%]测试方法2
Test_demo02.py::Test_Class3::test_case1 PASSED [ 66%]测试方法1
Test_demo02.py::Test_Class3::test_case3 PASSED [100%]测试方法3
============================== 3 passed in 0.02s ==============================
10.setup、teardown
setup_class()和 teardown_class()函数
需要定义在测试类中,定义在类外不起作用。
setup_class()定义场景,比如:创建日志对象,创建数据库的连接,创建接口的请求对象等。
teardown_class()定义场景,比如:销毁日志对象,销毁数据库的连接,销毁接口的请求对象。
"""
函数需要定义在测试类中,定义在类外不起作用。
setup_method()和 teardown_method(),在每个测试方法之前/之后执行。定义场景,比如:打开浏览器/关闭浏览器。
setup_class()定义场景,比如:创建日志对象,创建数据库的连接,创建接口的请求对象等。
teardown_class()定义场景,比如:销毁日志对象,销毁数据库的连接,销毁接口的请求对象。
"""
import pytest
class Test_setUp_tearDown:
# 方法级,前置函数
def setup_method(self):
# print("setup_method(self):在每个测试方法之前执行")
print("在每个测试方法之前执行")
# 方法级,后置函数
def teardown_method(self):
# print("teardown_method(self):在每个测试方法之后执行\n")
print("在每个测试方法之后执行")
# 类级,前置函数
def setup_class(self):
# print("setup_class(self):每个测试类之前执行一次\n")
print("每个测试类之前执行一次")
# 类级,后置函数
def teardown_class(self):
# print("teardown_class(self):每个测试类之后执行一次")
print("每个测试类之后执行一次")
# 测试用例a
def test_a(self):
print("test_a方法")
assert True
# 测试用例b
def test_b(self):
print("test_b方法")
assert True
if __name__ == '__main__':
pytest.main()
pytest钩子函数
在pytest中,钩子函数是一种特殊的函数,用于在测试执行过程中的特定阶段插入自定义逻辑。pytest提供了许多内置的钩子函数,这些钩子函数允许您在测试的不同阶段进行自定义操作。以下是pytest中常用的钩子函数及其作用
1.作用在类以外的钩子函数
1 setup()/tear_down()
def setup(): print("这是一个setup")
def teardown(): print("这是一个teardown")
2 setup_module()/teardown_module()
setup_module():在测试模块开始之前运行,用于设置模块级别的资源或配置。可以在该钩子函数中执行一次性的模块设置。
teardown_module():在测试模块结束之后运行,用于清理模块级别的资源或配置。可以在该钩子函数中执行一次性的模块清理。
def setup_module(self):
print("这个是模块级别的setup_module")
def teardown_module(self):
print("这个是模块级别的teardown_module")
3 setup_function/teardown_function
每条用例执行前执行一次,不会作用于class中的test_case
setup_function():在每个测试函数开始之前运行,用于设置单个测试函数的资源或配置。可以在该钩子函数中执行每个测试函数的准备工作。
teardown_function():在每个测试函数结束之后运行,用于清理单个测试函数的资源或配置。可以在该钩子函数中执行每个测试函数的清理工作。
def setup_function()
print("setup_function模块中每条用例执行前执行一次!")
def teardown_function():
print("teardown_function 模块中每条用例执行后执行一次!")
2.作用在类中的钩子函数
setup_class():在每个测试类开始之前运行,用于设置单个测试类的资源或配置。可以在该钩子函数中执行每个测试类的准备工作。
teardown_class():在每个测试类结束之后运行,用于清理单个测试类的资源或配置。可以在该钩子函数中执行每个测试类的清理工作。
setup_method():在每个测试方法开始之前运行,用于设置单个测试方法的资源或配置。可以在该钩子函数中执行每个测试方法的准备工作。
teardown_method():在每个测试方法结束之后运行,用于清理单个测试方法的资源或配置。可以在该钩子函数中执行每个测试方法的清理工作。
3.pytest_runtest_makereport 钩子函数
pytest_runtest_makereport
是一个重要的钩子,它在测试运行期间被调用,用于生成测试报告。通过覆盖这个钩子,你可以自定义测试报告的行为,例如在测试失败时执行某些操作,或者收集额外的信息。
示例
import pytest
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
# execute all other hooks to get the report object
outcome = yield
rep = outcome.get_result()
# we only look at actual failing test calls, not setup/teardown
if rep.when == "call" and rep.failed:
# 自定义逻辑:当测试失败时的操作
print(f"Test {item.name} failed")
# 你可以在这里添加更多的逻辑,例如记录日志、发送邮件等
在这个示例中,我们使用
@pytest.hookimpl
装饰器定义了一个pytest_runtest_makereport
钩子函数。参数tryfirst=True
表示这个钩子应该尽可能早地被调用,而hookwrapper=True
表示这是一个钩子包装器,它会先执行其他注册的钩子函数,然后执行自己的逻辑。
钩子详解
item
:当前正在运行的测试项。call
:当前测试阶段(setup、call 或 teardown)。rep
:测试报告对象,包含测试的结果信息。
示例中的逻辑
outcome = yield
:这部分代码使用yield
来执行其他注册的钩子函数,并获取它们的结果。这是hookwrapper
的典型用法。rep = outcome.get_result()
:获取测试报告对象。条件判断:if rep.when == "call" and rep.failed:
检查当前阶段是否为测试执行阶段(而非 setup 或 teardown),并且测试是否失败。自定义逻辑:在测试失败时执行自定义的逻辑,例如打印一条消息。
完整的插件示例
如果你需要将这个钩子放入一个插件中,可以创建一个
.py
文件(例如my_plugin.py
),并在其中定义这个钩子:
import pytest
class MyPlugin:
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(self, item, call):
# execute all other hooks to get the report object
outcome = yield
rep = outcome.get_result()
# we only look at actual failing test calls, not setup/teardown
if rep.when == "call" and rep.failed:
# 自定义逻辑:当测试失败时的操作
print(f"Test {item.name} failed")
# 你可以在这里添加更多的逻辑,例如记录日志、发送邮件等
def pytest_configure(config):
config.pluginmanager.register(MyPlugin(), "my_plugin")
def pytest_unconfigure(config):
plugin = getattr(config, "my_plugin", None)
if plugin is not None:
config.pluginmanager.unregister(plugin)
在这个示例中,我们定义了一个 MyPlugin
类,并在其中实现了 pytest_runtest_makereport
钩子。我们还在 pytest_configure
和 pytest_unconfigure
函数中注册和注销插件。
通过这种方式,你可以轻松地扩展 pytest 的功能,自定义测试报告的行为。
4 pytest_sessionfinish(session, exitstatus) 钩子函数
pytest_sessionfinish
是 pytest 提供的一个钩子(hook),它允许你在整个测试会话结束时执行一些操作。这个钩子在所有测试项运行完毕后被调用,但在此之前所有测试收集、设置(setup)、执行以及清理(teardown)都已经完成。这意味着你可以利用这个钩子来做一些总结性的工作,比如输出一些统计信息,关闭资源,清理环境等。
这个钩子有两个参数:
session: 一个
Session
对象,提供了对当前测试会话的信息访问。exitstatus: 一个整数,表示测试会话的退出状态码。这可以用来决定脚本的退出状态,例如是否成功执行。
如何使用
pytest_sessionfinish
下面是一个简单的例子来展示如何使用
pytest_sessionfinish
钩子:
import pytest
def pytest_sessionfinish(session, exitstatus):
# 在这里添加你的逻辑
print("All tests have finished.")
print(f"Exit status: {exitstatus}")
# 你也可以根据 exitstatus 决定做一些不同的事情
if exitstatus == 0:
print("All tests passed.")
else:
print("Some tests did not pass.")
更复杂的用法
如果你想要创建一个插件,可以像这样定义
pytest_sessionfinish
钩子:
import pytest
class MyPlugin:
def pytest_sessionfinish(self, session, exitstatus):
print("All tests have finished.")
print(f"Exit status: {exitstatus}")
def pytest_configure(config):
# 注册插件
config.pluginmanager.register(MyPlugin(), "my_plugin")
def pytest_unconfigure(config):
# 清理插件
plugin = getattr(config, "my_plugin", None)
if plugin is not None:
del config.my_plugin
config.pluginmanager.unregister(plugin)
Session 对象
session
参数是一个pytest.Session
实例,它提供了许多有用的方法和属性来访问关于测试会话的信息。例如,你可以使用session.items
获取测试项列表,session.testsfailed
获取失败的测试数量,以及其他有用的统计信息。
Exit Status
exitstatus
是一个整数,表示测试会话的退出状态。常见的值包括:
0: 所有测试通过。1: 测试失败或命令行选项无效。2: 用户中断(Ctrl+C)。5: 内部错误。
你可以根据这个状态码来决定后续的动作,例如发送通知或更新数据库的状态。
通过使用
pytest_sessionfinish
钩子,你可以确保在测试会话结束后执行一些必要的清理工作或通知操作。
pytest+allure测试报告(图文详解)
0.入口python文件执行pytest程序,并生成报告展示
os.system('python -m pytest --alluredir ./allure --clean-alluredir')
time.sleep(3)
os.system('allure serve ./allure')
说明:
python -m pytest: -m使用pytest模块执行
--alluredir ./allure:将测试结果保存到
allure
目录中.(或者使用 --alluredir=./allure),是pytest-allure-adaptor插件
中的选项。
--clean-alluredir:在保存测试结果之前先清理 allure 目录,是
插件pytest-allure-adaptor
中的选项。
1.安装allure
下载地址:Releases · allure-framework/allure2 · GitHub
解压后,运行 allure.bat,会弹出一个黑框一闪而过(闪的太快,没有截到图~~)
2.配置环境变量
allure安装路径: C:\D\soft\allure-2.26.0\bin path中
cmd中输入allure,allure --version,查看环境变量是否配置成功
3.下载allure-pytest插件
下载 pip install allure-pytest
查看 pip show allure-pytest
4.执行自动化用例,生成allure报告所需文件
执行用例,并指定生成allure报告路径,命令如下:
pytest Test_demo02.py -s -q --alluredir=./result
alluredir 指定<code>存放allure报告的路径
如图,生成两个文件夹:pytest_cache/result
result文件夹中三个json文件,对应用例中的三条case。
5.查看报告方式两种
方式一:可以通过allure解析json文件,使用命令查看报告
allure serve ./result (指定result文件夹路径)
会自动打开浏览器,展示allure报告
方式二:通过结果生成报告
allure generate ./allure -o ./allure-report --clean
./allure: pytest执行测试报告生成的数据文件路径
-o ./allure-report: 输出报告到此路径
--clean:<code>--clean 参数的作用是在生成新报告之前清理目标目录(也就是报告输出目录)。这意味着如果目标目录 ( ./allure-report) 中已经存在旧的报告文件,使用 --clean
参数会先删除这些旧文件,然后再生成新的报告。
打开报告
allure open -h 127.0.0.1 -p 8883 ./report/
6.QA-allure serve ./result/报错的解决思路
pycharm的终端输入:allure serve ./result/
allure报错:‘allure‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
解决思路:
没有下载allure,只是安装了allure-pytest插件安装allure后,检查是否配置allure的环境变量到path配置环境变量后,需要重启pycharm,可能是环境变量没有同步过来导致。关闭防火墙开关。
7.allure常用注解
实例如下
import pytest
from allure_commons.types import LinkType, Severity
@allure.parent_suite('我是parent_suite')
@allure.suite('我是suite')
@allure.sub_suite('我是sub_suite')
@allure.epic('我是epic')
@allure.feature('我是feature')
@allure.story('我是story')
class TestAllureDemo:
@allure.step('我是断言')
def assert_one(self, a, b):
assert a == b
@allure.id('我是id')
@allure.title('我是title')
@allure.link('https://www.baidu.com/', LinkType.ISSUE, '我是link_ISSUE')
@allure.label('我是label')
@allure.issue('https://www.baidu.com/', '我是issue')
@allure.description('我是description')
@allure.severity(Severity.BLOCKER)
@allure.tag('我是tag')
@allure.testcase('https://www.baidu.com/', 'testcase')
def test_01(self):
self.assert_one(1, 1)
@allure.id('我是id')
@allure.title('我是title')
@allure.link('https://www.baidu.com/', LinkType.LINK, '我是link')
@allure.label('我是label')
@allure.issue('https://www.baidu.com/', '我是issue')
@allure.description('我是description')
@allure.severity('我是severity')
@allure.tag('我是tag')
@allure.testcase('https://www.baidu.com/', '我是testcase')
def test_02(self):
allure.dynamic.mro()
allure.dynamic.title('我是修改后的title')
allure.dynamic.link('https://www.baidu.com/', LinkType.LINK, '我是修改后的link')
allure.dynamic.label('我是修改后的label')
allure.dynamic.issue('https://www.baidu.com/', '我是修改后的issue')
allure.dynamic.description('我是修改后的description')
allure.dynamic.severity('我是修改后的severity')
allure.dynamic.tag('我是修改后的tag')
allure.dynamic.testcase('https://www.baidu.com/', '我是修改后的testcase')
assert 1 > 1
生成的报告如下
case1: test_01
case2: test_02
遇到的问题
问题1:pytest执行的case,如果返回结果有中文,获取数据显示unicode编码格式
原因:是pytest默认将输出报告 视为ASCII字符串,并在测试报告中按原样显示。由于中文字符不属于ASCII字符范围,因此pytest会将其转换为Unicode编码表示。
解码后,pytest的执行报告才能正常显示中文。
使用语句:result = response.content.decode("unicode-escape")
问题2:在pycharm/idea中,执行程序运行:pytest 命令执行用例时, 提示:PermissionError: [Errno 13] Permission denied: 'C:\\Program Files\\Python310\\lib\\site-packages\\comtypes\\gen\\_944DE083_8FB8_45CF_BCB7_C477ACB2F897_0_1_0.py'
<code>Program Files 目录通常是一个系统受保护的目录,在默认情况下,普通用户可能没有足够的权限去读取或修改其中的文件。这可能是为什么 pytest 会遇到权限拒绝的原因。
以下是你可以尝试的一些解决方案:
1. 使用管理员权限运行 pytest
在 Windows 上,你可以尝试以管理员身份运行命令提示符或 PowerShell,然后重新运行你的测试。
打开命令提示符或 PowerShell。
右键点击选择“以管理员身份运行”。
在命令提示符中运行 pytest 命令。
2. 检查 Python 安装路径
如果你的 Python 安装在 Program Files 目录下,考虑将 Python 重装到一个不需要管理员权限的目录,比如 C:\Python310。
3. 虚拟环境
使用虚拟环境可以避免直接在系统级别的 Python 安装上进行操作。这样可以减少权限问题,并且让你的项目依赖更加隔离。
创建一个新的虚拟环境。
激活虚拟环境。
在虚拟环境中安装所需的包。
在虚拟环境中运行你的测试。
问题2.1:为什么之前执行pytest,没有提示权限问题
如果你之前能够正常执行 pytest 测试,而现在出现了权限错误,可能有几个潜在的原因导致这一变化。这里有一些可能性:
系统更新或安全策略变化:
最近是否有过系统更新?有时操作系统或防病毒软件的更新会改变某些文件的权限设置。是否启用了新的安全策略或防火墙规则,限制了对某些文件的访问?
Python 版本或依赖库更新:
你是否更新了 Python 版本或 comtypes
库?新版本可能改变了某些行为或文件生成的位置。更新依赖库可能导致一些文件的生成位置或方式发生变化,从而影响到权限。
虚拟环境的变化:
如果你在虚拟环境中工作,是否有任何环境的变化?例如激活了不同的虚拟环境,或者虚拟环境的权限设置发生了变化。
测试代码的变更:
最近是否修改了测试代码或相关依赖?某些修改可能会触发不同的文件访问逻辑。如果你的测试代码或框架最近有所更新,这些更新可能会引入新的行为或依赖。
文件系统缓存或锁定状态:
有时候文件系统的缓存或锁定状态可能导致暂时性的权限问题。重启计算机或清理缓存可能会解决这类问题。
并发操作:
如果你的测试是在并发环境下运行的(例如多线程或多进程),其他进程可能正在使用或锁定这些文件。
环境变量或配置文件:
检查是否有环境变量或配置文件的更改,这些更改可能会影响文件的访问权限。
IDE 或构建工具的更改:
如果你是通过 IDE 或者构建工具(如 Jenkins)运行测试,这些工具的更新或配置更改也可能导致此类问题。
结论:由于pycharm中环境变化导致,pytest引用的python环境不是预期的环境,修改为预期环境后,问题解决。
pytest引用错误的python环境为:C:\Program Files\python310,通过控制面板>程序和软件,没有查询到python310,直接手动删除C:\Program Files\python310文件夹后。
在pycharm>termianl,使用pip命令查看,可以正常引用到预期的环境了
C:/Users/sjy/AppData/Local/Programs/Python/Python39/python.exe
此时,执行程序运行:pytest 命令执行用例时,功能正常。
参考文档:pytest框架详解_pytest框架 cllections.abc-CSDN博客
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。