【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的函数名称 

<code> @pytest.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()修饰需要运行的用例(可以叠加使用多个装饰器)

<code> @pytest.fixture()

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_configurepytest_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常用注解

实例如下

<code>import 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博客



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。