当前位置: 首页 > news >正文

WEB UI自动化测试之Pytest框架学习

文章目录

  • 前言
  • Pytest简介
  • Pytest安装
  • Pytest的常用插件
  • Pytest的命名约束
  • Pytest的运行方式
    • Pytest运行方式与unittest对比
    • 主函数运行
    • 命令行运行
      • 执行结果代码说明
    • pytest.ini配置文件方式运行(推荐)
      • 使用markers标记测试用例
  • pytest中添加Fixture(测试夹具)
    • pytest中的setup与teardown
    • conftest
    • pytest中的fixtrue装饰器
      • pytest中的fixtrue装饰器的优势
      • Fixture装饰器的定义方式
      • fixtrue装饰器参数详解-scope
        • scope = “function”
        • scope = “class”
        • scope = “module”
      • fixtrue参数详解-autouse
  • 测试用例添加、加载、运行(对比unittest)
  • pytest跳过测试用例skip、skipif
    • @pytest.mark.skip
    • @pytest.mark.skipif
      • 跳过标记
  • Pytest参数化
    • 函数返回值作为参数
    • “笛卡尔积”,多个参数化装饰器
  • 输出测试报告
  • 预期失败函数
    • 作用
    • 应用场景
    • 语法与参数
  • 控制方法执行顺序
    • 简介
    • 安装 pytest-ordering
    • 使用方法
    • 示例
      • 示例1:基于 order 的执行顺序
      • 示例2:基于 before/after 的执行顺序
  • 失败重试
    • 简介
    • 安装
    • 使用方法
      • 装饰器方式
      • 参数添加运行方式
  • 参考目录


前言

阅读本文前请注意最后编辑时间,文章内容可能与目前最新的技术发展情况相去甚远。欢迎各位评论与私信,指出错误或是进行交流等。


在之前已经学习过用unittest测试框架,本文介绍另外一个目前主流的测试框架Pytest。

Pytest简介

官方文档介绍:

Pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.
官方地址:https://docs.pytest.org

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

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

Pytest安装

安装命令

pip install -U pytest

查看是否安装成功

pytest --version # 展示当前已安装版本

Pytest的常用插件

插件列表网址:https://plugincompat.herokuapp.com
包含很多插件包,大家可依据工作的需求选择使用。

Pytest的命名约束

1)模块名(py文件)通常被统一放在一个testcases文件夹中,必须是以test_开头或者_test.py结尾
2)测试类(class)必须以Test开头,并且不能带init方法,类里的方法必须以test_开头
3)测试用例(函数)必须以test_开头
此时,在执行pytest命令时,会自动从当前目录及子目录中寻找符合上述约束的测试函数来执行。
在这里插入图片描述

# 测试函数必须以test_开头(类以外)def test_demo1(self):print("测试用例1")# 测试类(class)必须以Test开头 
class TestDemo:# 类里的方法必须以test_开头def test_demo2(self):print("测试用例2")

Pytest的运行方式

Pytest运行方式与unittest对比

运行步骤Pytestunittest
导包导入pytest模块导入unittest模块
创建测试方法(不写在测试类中的)测试方法名称必须以test开头测试方法名称必须以test开头
创建测试类必须以Test开头,并且不能带init方法测试类的命名不做要求,但需要继承unittest.TestCase类。
添加测试固件(fixtrue 非必需)setUp()、tearDown()系列方法 、 fixtrue装饰器使用setUp()、tearDown()系列方法
测试类中定义测试方法(即测试用例)测试方法名称必须以test开头测试方法名称必须以test开头
执行测试用例通过主函数/命令行/配置文件 方式运行通过主函数 或者 使用TestSuite/TestLoader/TextTestRunner

主函数运行

import  pytest
#  创建测试方法(不写在测试类中的)
def test_01():print("啥也没有")
# 通过主函数方式运行
if __name__=='__main__':pytest.main()

main()中可使用的参数有:

参数描述案例
-v输出调试信息。如:打印信息 pytest.main([‘-v’,‘testcase/test_one.py’,‘testcase/test_two.py’])
-s输出更详细的信息,如:文件名、用例名pytest.main([‘-vs’,‘testcase/test_one.py’,‘testcase/test_two.py’])
-n多线程或分布式运行测试用例
-x只要有一个用例执行失败,就停止执行测试pytest.main([‘-vsx’,‘testcase/test_one.py’])
– maxfail出现N个测试用例失败,就停止测试pytest.main([‘-vs’,‘-x=2’,‘testcase/test_one.py’]
–html=report.html生成测试报告pytest.main([‘-vs’,‘–html=./report.html’,‘testcase/test_one.py’])
-m通过标记表达式执行
-k根据测试用例的部分字符串指定测试用例,可以使用and,or

命令行运行

文件路径:testcase/test_one.py

def test_a():print("啥也没有")assert 1==1

终端输入:pytest ./testcase/test_one.py --html=./report/report.html

命令行中可使用的参数有:

参数描述案例
-v输出调试信息。pytest -x ./testcase/test_one.py
-q输出简单信息。pyets -q ./testcase/test_one.py
-s输出更详细的信息,如:文件名、用例名pytest -s ./testcase/test_one.py
-n多线程或分布式运行测试用例
-x只要有一个用例执行失败,就停止执行测试pytest -x ./testcase/test_one.py
– maxfail出现N个测试用例失败,就停止测试pytest --maxfail=2 ./testcase/test_one.py
–html=report.html生成测试报告pytest ./testcase/test_one.py --html=./report/report.html
-k根据测试用例的部分字符串指定测试用例,可以使用and,or

执行结果代码说明

  • Exit code 0 所有用例执行完毕,全部通过
  • Exit code 1 所有用例执行完毕,存在Failed的测试用例
  • Exit code 2 用户中断了测试的执行
  • Exit code 3 测试执行过程发生了内部错误
  • Exit code 4 pytest 命令行使用错误
  • Exit code 5 未采集到可用测试用例文件

pytest.ini配置文件方式运行(推荐)

不管是mian执行方式还是命令执行,最终都会去读取pytest.ini文件。
配置有 pytest.ini 的工程, 只需要打开命令行输入pytest,即可进行测试。
在项目的根目录下创建pytest.ini文件,包含以下内容

[pytest]
addopts=-vs -m slow --html=./report/report.html
testpaths=./scripts
test_files=test_*.py
test_classes=Test*
test_functions=test_*
makerers=smock:冒烟测试用例regression: 回归测试标记
参数作用
[pytest]用于标志这个文件是pytest的配置文件
addopts命令行参数,多个参数之间用空格分隔
testpathspytest要进行测试的工作目录
test_files工作目录下要进行测试的文件名匹配规则
test_classes工作目录下 测试文件中 可执行类的名称匹配规则
test_functions测试类中 测试方法名的匹配规则
markers用例标记,自定义mark,需要先注册标记

使用markers标记测试用例

在 pytest 中,markers 是一种非常有用的功能,它可以对测试用例进行标记,以便实现更灵活的测试执行和分组等操作。
**在pytest.ini文件中自定义 markers。**例如:

makerers=
smock:冒烟测试用例
regression: 回归测试标记

这里创建了冒烟测试和回归测试的标记,我们就可以使用这个标记为测试用例进行标记。如下所示:

import pytest@pytest.mark.smoke
def test_01():assert 1==1@pytest.mark.regression
def test_02():assert 2==2

在这里插入图片描述
如果不想每次都输入-m smoke,我们可以把这部分放到pytest.ini下。
在这里插入图片描述

pytest中添加Fixture(测试夹具)

pytest中的setup与teardown

Pytest也提供了类似于unittest中 setup、teardown的方法,并且分为了五类:

  • 模块级别:setup_module、teardown_module
  • 函数级别:setup_function、teardown_function,不在类中的方法
  • 类级别:setup_class、teardown_class
  • 方法级别:setup_method、teardown_method
  • 方法细化级别:setup、teardown

我们直接来看代码和运行结果

#!/usr/bin/env python
# -*- coding: utf-8 -*-import pytestdef setup_module():print("=====整个.py模块开始前只执行一次:打开浏览器=====")def teardown_module():print("=====整个.py模块结束后只执行一次:关闭浏览器=====")def setup_function():print("===每个函数级别用例开始前都执行setup_function===")def teardown_function():print("===每个函数级别用例结束后都执行teardown_function====")def test_one():print("one")def test_two():print("two")class TestCase():def setup_class(self):print("====整个测试类开始前只执行一次setup_class====")def teardown_class(self):print("====整个测试类结束后只执行一次teardown_class====")def setup_method(self):print("==类里面每个用例执行前都会执行setup_method==")def teardown_method(self):print("==类里面每个用例结束后都会执行teardown_method==")def setup(self):print("=类里面每个用例执行前都会执行setup=")def teardown(self):print("=类里面每个用例结束后都会执行teardown=")def test_three(self):print("three")def test_four(self):print("four")if __name__ == '__main__':pytest.main(["-q", "-s", "-ra", "setup_teardown.py"])

在这里插入图片描述

注意,从执行结果我们可以看到:

  • 模块级别:setup_module、teardown_module 在整个.py模块开始前和结束后只执行一次;
  • 函数级别:setup_function、teardown_function,对不在类中的方法生效。在每个函数级别用例开始前和结束后执行;
  • 类级别:setup_class、teardown_class,整个测试类开始前和结束后执行一次;
  • 方法级别:setup_method、teardown_method,测试类里面每个测试用例开始前和结束后都执行一次;
  • 方法细化级别:setup、teardown,跟前面方法级别使用类似,不过setup在setup_method之后执行,teardown在teardown_method之前执行;
    Pytest除了与unittest中类似的提供了setup和teardown方法外,还提供了使用装饰器的格式来为测试用例添加Fixture。

conftest

在介绍装饰器格式的Fixture前,先介绍conftest。
Conftest它是pytest的一个组件,用于配置测试环境和参数。
因此,conftest.py 文件是存放测试夹具(Fixtures)的理想场所。
测试夹具就像是测试用例执行时的得力助手,能够为测试提供各种必要的资源,如数据、对象、环境等。
通过在 conftest.py 中定义测试夹具,我们可以在多个测试模块中轻松地共享和复用这些资源,避免了在每个测试文件中重复编写相同的准备代码,大大提高了代码的可维护性和测试效率。

  • 运行测试之前,pytest会自动识别并执行conftest.py文件中的配置。
  • 运行测试之前,pytest 会默认读取 conftest.py里面的所有 fixture
  • conftest.py 文件名称是固定的,不能改动
  • conftest.py 只对同一个 package 下的所有测试用例生效
  • 不同目录可以有自己的 conftest.py,一个项目中可以有多个 conftest.py
  • 测试用例文件中不需要手动 import conftest.py,pytest 会自动查找

** 各级工作目录下的conftest.py**
在这里插入图片描述

pytest中的fixtrue装饰器

我们可以在conftest.py中,或者是测试模块中定义fixtrue装饰器。

如果有以下场景:1.用例一需要执行登录操作;2.用例二不需要执行登录操作;3.用例三需要执行登录操作,则unittest框架中的setup和teardown则不满足要求。而Pytest中的fixture装饰器就可以解决这一问题

pytest中的fixtrue装饰器的优势

  • 命名方式灵活,不限于setup和teardown两种命名
  • conftest.py可以实现数据共享,不需要执行import 就能自动找到fixture装饰器

Fixture装饰器的定义方式

@pytest.fixture(scope = "function",params=None,autouse=False,ids=None,name=None)

fixtrue装饰器参数详解-scope

用于控制Fixture装饰器的作用范围,默认取值为function(函数级别)

取值范围说明
function函数级每一个函数或方法都可以调用,在测试用例执行前生效。
class模块级测试类内的测试用例可以调用,具体在何处生效得视情况而定
module模块级每一个.py文件调用一次, 在第一次调用fixtrue的地方生效
session会话级每次会话只运行一次,会话内所有方法及类,模块都共享这个fixtrue
scope = “function”
  • 场景一:做为参数传入
import pytest@pytest.fixture()
def login():print("打开浏览器")a = "account"return a@pytest.fixture()
def logout():print("关闭浏览器")class TestLogin:#传入lonin fixturedef test_001(self, login):print("001传入了loging fixture")assert login == "account"#传入logout fixturedef test_002(self, logout):print("002传入了logout fixture")def test_003(self, login, logout):print("003传入了两个fixture")def test_004(self):print("004未传入仍何fixture哦")if __name__ == '__main__':pytest.main()

在这里插入图片描述

从运行结果可以看出,fixture函数做为参数传入时,会先执行所有的fixture函数。

  • 场景二:Fixture的相互调用
import pytest@pytest.fixture()
def account():a = "account"print("第一层fixture")return a#Fixture的相互调用一定是要在测试类里调用这层fixture才会生次,普通函数单独调用是不生效的
@pytest.fixture()   
def login(account):print("第二层fixture")class TestLogin:def test_1(self, login):print("直接使用第二层fixture,返回值为{}".format(login))def test_2(self, account):print("只调用account fixture,返回值为{}".format(account))if __name__ == '__main__':pytest.main()

在这里插入图片描述

1.即使fixture之间支持相互调用,但普通函数直接使用fixture是不支持的,一定是在测试类中的测试函数内调用才会逐级调用生效
2.有多层fixture调用时,最先执行的是最内层fixture,而不是先执行传入测试函数的fixture
3.上层fixture的值不会自动return,这里就类似函数相互调用一样的逻辑

scope = “class”

当fixture的作用范围是class时, 具体如何生效要根据fixture的写法来决定。一共有两种情况
1.当测试类内的每一个测试方法都调用了fixture,fixture只在该class下所有测试用例执行前执行一次
2.测试类下面只有部分测试方法使用了fixture函数名。fixture只在该class下第一个使用fixture函数的测试用例执行前执行一次

  • 场景一: 每一个测试方法都调用了fixture
import pytest
# fixture作用域 scope = 'class'
@pytest.fixture(scope='class')
def login():print("scope为class")class TestLogin:def test_1(self, login):print("用例1")def test_2(self, login):print("用例2")def test_3(self, login):print("用例3")if __name__ == '__main__':pytest.main()

在这里插入图片描述

  • 场景二: 部分测试方法都调用了fixture
import pytest
@pytest.fixture(scope='class')
def login():a = '123'print("输入账号密码登陆")class TestLogin:def test_1(self):print("用例1")def test_2(self, login):print("用例2")def test_3(self, login):print("用例3")def test_4(self):print("用例4")if __name__ == '__main__':pytest.main()

在这里插入图片描述

scope = “module”
import pytest@pytest.fixture(scope='module')
def login():print("fixture范围为module")def test_01():print("用例01")def test_02(login):print("用例02")class TestLogin():def test_1(self):print("用例1")def test_2(self):print("用例2")def test_3(self):print("用例3")if __name__ == '__main__':pytest.main()

在这里插入图片描述

fixtrue参数详解-autouse

默认False
若为True,每个测试函数都会自动调用该fixture,无需传入fixture函数,作用范围跟着scope走
autouse=ture的效果如下:

在这里插入图片描述

测试用例添加、加载、运行(对比unittest)

  • 如果要运行多个测试用例,unittest提供了TestSuite/TestLoader的方法加载测试用例,随后利用TextTestRunner执行测试用例套件。
  • Pytest 可通过pytest.ini配置文件 确定测试的工作目录。对测试方法、测试类、测试模块的命名进行了约束后,在配置文件中写好名称匹配规则后,通过主函数或者命令行的方式运行。Pytest会自动加载符合条件的测试用例并运行。

pytest跳过测试用例skip、skipif

@pytest.mark.skip

跳过执行测试,有可选参数 reason:跳过的原因,会在执行结果中打印
@pytest.mark.skip可以加在函数上,测试类上,测试类中的方法上
如果加在测试类上面,测试类里面的所有测试用例都不会执行

import pytest@pytest.mark.skip(reason="不执行该用例!!因为没写好!!")
def test_case01():print("skip加在函数上")@pytest.mark.skip(reason="skip加在测试类上") 
class TestSkip:def test_1(self):print("%% 不会执行 %%")def test_2(self):print("%% 不会执行 %%")class Test1:@pytest.mark.skip(reason="skip加在测试类中的方法上")def test_1(self):print("%% 不会执行 %%")

@pytest.mark.skipif

方法:
skipif(condition, reason=None)
参数:
condition:跳过的条件,必传参数
reason:标注原因,必传参数
使用方法:
@pytest.mark.skipif(condition, reason=“xxx”)

 
import pytest
class Test_ABC:def setup_class(self):print("------->setup_class")def teardown_class(self):print("------->teardown_class")def test_a(self):print("------->test_a")assert 1@pytest.mark.skipif(condition=2>1,reason = "跳过该函数")def test_b(self):print("------->test_b")assert 0
执行结果:test_abc.py ------->setup_class------->test_a #只执行了函数test_a.------->teardown_classs # 跳过函数

跳过标记

可以将 pytest.mark.skip 和 pytest.mark.skipif 赋值给一个变量,在不同模块之间共享这个变量。可以用一个单独的文件去管理这些通用标记

# 标记
skipmark = pytest.mark.skip(reason="不能在window上运行=====")
skipifmark = pytest.mark.skipif(sys.platform == 'win32', reason="不能在window上运行啦啦啦=====")@skipmark
class TestSkip_Mark(object):@skipifmarkdef test_function(self):print("测试标记")def test_def(self):print("测试标记")@skipmark
def test_skip():print("测试标记")

Pytest参数化

@pytest.mark.parametrize(argnames, argvalues)# argnames 含义:参数列表
# argvalues 含义:参数值列表# 例如:
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):print(f"测试数据{test_input},期望结果{expected}")assert eval(test_input) == expected
# 参数列表就是"test_input,expected" 与函数中的形参一致。 参数值必须是一个列表,且由于有两个参数,需要以元组的方式存放
# 如果只有一个参数,如:@pytest.mark.parametrize(“username”, [“yy”, “yy2”, “yy3”])
# 如果有多个参数例,则需要用元组来存放值,一个元组对应一组参数的值

函数返回值作为参数

import pytest
def return_test_data():# 中间代码掠过return [(1,2),(0,3)]
class Test_ABC:def setup_class(self):print("------->setup_class")def teardown_class(self):print("------->teardown_class")@pytest.mark.parametrize("a,b",return_test_data()) # 使用函数返回值的形式传入参数值def test_a(self,a,b):print("test data:a=%d,b=%d"%(a,b))assert a+b == 3执行结果:test_abc.py ------->setup_classtest data:a=1,b=2 # 运行第一次取值 a=1,b=2.test data:a=0,b=3 # 运行第二次取值 a=0,b=3.------->teardown_class

“笛卡尔积”,多个参数化装饰器

# 笛卡尔积,组合数据
data_1 = [1, 2, 3]
data_2 = ['a', 'b']
@pytest.mark.parametrize('a', data_1)
@pytest.mark.parametrize('b', data_2)
def test_parametrize_1(a, b):print(f'笛卡尔积 测试数据为 : {a},{b}')

输出测试报告

目前主流的与Pytest搭配的测试报告是Allure,Allure是一个灵活轻量级多语言测试报告工具。
关于Allure会在另外一篇博文中介绍。

预期失败函数

作用

期望测试用例是失败的,但是仍会运行此测试用例,并且也不会影响其他测试用例的的执行。
如果预期失败的测试用例执行失败,则输出结果是xfail(不会额外显示出错误信息)
如果预期失败的测试用例执行成功,则输出结果是xpass。(不符合预期的成功)

应用场景

  • 用例功能不完善,或者用例执行一直失败。
  • 对尚未实现的功能进行测试时。
  • 尚未修复的错误进行测试时。

语法与参数

@pytest.mark.xfail(condition=None, reason=None);

  • condition:表示预期结果,然后用例实际执行的结果,与预期结果对比,会出现4种测试结果状态。
    failed, passed, xfailed, xpassed。
    提示:condition可以等于True或者False,也可以等于一个表达式,如:condition=1>2等。

  • reason:说明用例标记为预期失败的原因, 默认为None。(必填)

另外,我们也可以通过pytest.xfail方法在用例执行过程中直接标记用例结果为XFAIL,并跳过剩余的部分:

def test_function():if not valid_config():pytest.xfail("failing configuration (but should work)")

控制方法执行顺序

在使用 Pytest 进行单元测试或集成测试时,通常测试用例的执行顺序是自动排序的。不过在某些情况下,特别是当测试用例存在依赖关系时,我们可能希望自定义测试的执行顺序。为了解决这一需求,Pytest 提供了一个实用插件——pytest-ordering。

简介

pytest-ordering 是 Pytest 的一个插件,允许我们自定义测试用例的执行顺序。通过为测试用例指定顺序标记,可以在确保测试独立性的同时,满足特定的执行需求。

安装 pytest-ordering

pip install pytest-ordering

使用方法

在安装插件后,可以使用 @pytest.mark.run 标记来为测试用例设置执行顺序。常用的执行顺序标记有以下几种:

  • @pytest.mark.run(order=N):使用具体的整数值 N 定义执行顺序,数字越小,优先级越高。
  • @pytest.mark.run(before=‘test_name’):表示当前测试用例应在指定测试 test_name 之前运行。
  • @pytest.mark.run(after=‘test_name’):表示当前测试用例应在指定测试 test_name 之后运行。

示例

示例1:基于 order 的执行顺序

import pytest@pytest.mark.run(order=2)
def test_case_1():assert True@pytest.mark.run(order=1)
def test_case_2():assert True@pytest.mark.run(order=3)
def test_case_3():assert True

执行顺序将按照 order 的值来确定,因此运行顺序为:test_case_2 -> test_case_1 -> test_case_3。

示例2:基于 before/after 的执行顺序

import pytest@pytest.mark.run(before="test_case_2")
def test_initial_setup():assert Truedef test_case_1():assert True@pytest.mark.run(after="test_case_1")
def test_case_2():assert True

在此示例中,执行顺序为 test_initial_setup -> test_case_1 -> test_case_2。

失败重试

有时候用例失败并非代码问题,而是由于网络等因素,导致请求失败。从而降低了自动化用例的稳定性,最后还要花时间定位到底是自身case的原因还是业务逻辑问题,还是其他原因,增加了定位成本。
增加容错机制,失败重试,会解决大部分由于网络原因、服务重启等原因造成的case失败问题。那该如何增加失败重试机制呢?使用pytest-rerunfailures插件来实现失败重试功能。

简介

pytest-rerunfailures 是一个基于 pytest 框架的插件,它允许我们对测试用例进行失败重试。当一个测试用例失败时,插件会自动重新运行失败的测试用例,直到达到预定的重试次数或测试用例通过为止。这样可以增加用例的稳定性,并减少因为偶发性问题导致的测试失败。

文档地址:
https://github.com/pytest-dev/pytest-rerunfailures
https://pypi.org/project/pytest-rerunfailures/#description

安装

pip install pytest-rerunfailures 

使用方法

装饰器方式

import pytest
# 参数:reruns=n(重新运行次数),reruns_delay=m(每次重试之间的延迟时间)
@pytest.mark.flaky(reruns=3, reruns_delay=2)
def test_case():
assert 1 == 2

运行case,看一下执行结果:

# 执行命令
pytest -s -v test_demo.py::test_case# 结果
RERUN
test_dir/test_demo.py::test_case RERUN
test_dir/test_demo.py::test_case RERUN
test_dir/test_demo.py::test_case FAILED

可以看到,重试了3次,最终结果为失败。

参数添加运行方式

pytest-rerunfailures支持使用命令行选项和配置文件的方式进行配置。
并且是对所有的测试用例生效

# 在命令行运行中添加参数 --reruns 3 --reruns-delay 2
pytest -s -v --reruns 3 --reruns-delay 2 test_demo.py::test_case# 主函数运行中添加参数
pytest.main(["-s", "-v", "--reruns", "3", "--reruns-delay", "2", "test_demo.py::test_case"])# 或者在pytest.ini配置文件addopts中添加参数
addopts=-vs --reruns 3 --reruns-delay 2 --html=./report/report.html

注意:如果指定了用例的重新运行次数,则在命令行添加 --reruns 对这些用例是不会生效的


参考目录

https://www.bilibili.com/video/BV18Q4y1y7v3
https://blog.csdn.net/kkkkk19980517/article/details/139065687
https://blog.csdn.net/lovedingd/article/details/98952868
https://blog.csdn.net/qq_42610167/article/details/101204066
https://blog.csdn.net/qq_45609369/article/details/140007322
https://blog.csdn.net/m0_63463510/article/details/145914339
https://blog.csdn.net/m0_37135615/article/details/146145220
https://blog.csdn.net/fyyaom/article/details/102938704
https://blog.csdn.net/cebawuyue/article/details/144106872
https://blog.csdn.net/weixin_56331124/article/details/145190520

相关文章:

  • 前端取经路——框架修行:React与Vue的双修之路
  • 稳定性_李雅普诺夫——Lyapunov直接法
  • 数据结构-非线性结构-二叉树
  • Qt开发经验 --- 避坑指南(8)
  • 10. CSS通配符与选择器权重深度解析:以《悯农》古诗为例
  • 新能源汽车CAN通信深度解析:MCU、VCU、ECU协同工作原理
  • 图漾相机——Sample_V2示例程序(待补充)
  • 人工智能在网络安全中的重要性
  • 湖北理元理律师事务所的企业债务重组实践:挽救实体经济的法律处方
  • Android7 Input(六)InputChannel
  • 网络安全赛题解析
  • 手撕基于AMQP协议的简易消息队列-1(项目介绍与开发环境的搭建)
  • 65.微服务保姆教程 (八) 微服务开发与治理实战
  • B站搜索关键词全攻略:掌握B站搜索关键词的运作机制
  • Andorid 文件打印功能
  • 服务器托管的常见问题
  • c语言与c++到底有什么区别?
  • 【STM32单片机】#15 WDG看门狗
  • pygame联网飞机大战游戏实现
  • Elastic:什么是 AIOps?
  • 上海证监局规范辖区私募经营运作,6月15日前完成自评自纠
  • 金地集团:今年前4个月实现销售额109.3亿元,同比下降52.44%
  • 105岁八路军老战士、抗美援朝老战士谭克煜逝世
  • 西南大学教授、重庆健美运动奠基人之一李启圣逝世
  • 苹果Safari浏览器上的搜索量首次下降
  • 常州市委原常委、组织部部长陈翔调任江苏省民宗委副主任