pytest 框架

pytest是一个单测框架;能对定义的测试对象进行测试,并且可以针对测试对象进行前后置处理,对测试结果进行断言,对执行过程中的异常进行干预,并且可以收集测试结果以生成xml格式的测试报告

大纲

1
2
3
4
5
6
7
8
9
10
原理
使用场景
如何使用
①调度/执行
②前后置处理(固件)
③用例断言
④异常处理
⑤参数化
⑥定制报告
⑦性能-缓存

原理

pytest是一套单测框架;有着自己的巡检方法,他会自动查找整个包中以test开头/结尾的模块,并查找其中test开头/结尾的方法/类(类很特殊必须要以Test开头,且类中不能有__init__方法),全部保存在内存中,在触发执行时,会根据调度指令来确定自动执行的用例范围,来进行执行; 同时执行用例时做了装饰器操作,将用例作为参数传递到pytest框架中执行。

使用场景

  • 用例自动单测场景: 如接口自动化、UI自动化、各类用例场景;
  • 通用前后置处理场景: 如数据库操作前的建立连接,操作完成后的断开连接;
  • 参数化操作场景: 如多设备操作、各种UI操作、各种接口操作;

如何使用

分为:调度/执行、前后置处理(固件)、用例(断言+异常处理+跳过+标记)、参数化、定制报告、性能(缓存操作)

调度/执行

调度有两种方式:命令行、pytest.main()

  • pytest.main():实际也是调用命令行来进行的操作,我们程序一般使用pytest.main()来调度;注意pytest.main(['-m','对象']);第一个参数是选项,第二个参数是对象;pytest.main()会将当前模块加入缓存,因此不建议执行过程中调用多次,最好只调用一次,示例如下。

    • pytest.main([“-qq”], plugins=[MyPlugin()]) //指定一个插件运行
    • pytest.main([‘-sq’,’test_nodeid.py::TestNodeId::test_two[1-1]’])
  • 命令行调用:pytest 各选项如-rx 对象如test_1.py::test_fun

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    对象:可通过命令行执行特定包内的用例/特定目录下/特定模块/特定方法/特定方法的特定参数化参数
    pytest –pyargs pkg.testing
    pytest testing/pytest test_mod.py/pytest test_mod.py::test_fun
    pytest -q -s test_nodeid.py::TestNodeId::test_two[1-1]

    模糊匹配:执行含特定字符或(也可以是和)不含特定字符的模块/类/函数:
    pytest -k “_class and/or not two”

    还可以为用例添加标记。从而指定特定标记的用例:pytest -m 标记名
    @pytest.mark.标记名
    def test_one()
  • pytest自动巡检机制:pytest会自动化去查找到测试用例,他是按模块的首尾是否是test来判断的,模块中的类(类很特殊必须要以Test开头,且类中不能有__init__方法)/方法首尾是test则判定为测试用例,这些测试用例维护在内存中,以数组的形式维护,触发执行时会自动执行这些用例;用例执行顺序是按测试用例的名称从大到小来的,可以利用pytest-ordering插件来定制用例的执行顺序; 默认情况下执行pytest.main()时仅执行当前模块的用例,如果需要执行其他路径下的用例,可以指定路径。

  • 常用命令行选项

    • 查看结果
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      pytest -q							//-q选项可以查看精简版的测试报告
      pytest -r //(同-q只是可以过滤)显示精简的总结报告;-r后还要加一个参数,表示需要显示的内容,其他的会过滤,如-rfs(f是失败的,s是跳过的,显示失败的和跳过的实例)
      pytest -s //-s是--capture=no的快捷方式,是用来关闭输出(标准输出/标准错误)捕获,使得可以看到print()输出的内容
      pytest --capture=fd(默认捕获行为) //指定只捕获文件/接口层面的标准输出/标准错误
      pytest --capture=sys //指定只捕获系统级别的标准输出/标准错误
      pytest -l, --showlocals # 打印本地变量
      pytest --tb=auto # 默认模式
      pytest --tb=long # 尽可能详细的输出
      pytest --full-trace //比--tb=long更详细的输出模式
      pytest --tb=short # 更简短的输出
      pytest --tb=line # 每个失败信息总结在一行中
      pytest --tb=native # python的标准输出
      pytest --tb=no # 不打印失败信息
      pytest --pdb //失败时进入pdb诊断器模式
      pytest --trace //启动时就进入pdb诊断器模式
      pytest --durations=10 //获取执行最慢的十个测试用例
      pytest -vv //获取用例的执行时间
      pytest --show-capture //定义是否显示,标准输出、标准错误、或异常堆栈;支持的选项值有[no,stdout,stderr,log,all,默认为all]
      pytest --assert=plain选项 //关闭断言失败提示信息
      python -p no:faulthandler //默认是打开的,可以通过此命令关闭回溯信息当用例执行出现断错误或超时,faulthandler模块,可以展示Python脚本的回溯信息(回溯不是错误信息,此时程序也不会中断,只是打印此时的相关信息,类似监控);
      faulthandler_timeout=5 //(pytest.ini文件配置)可以配置超时时间,一旦超时则显示所有线程的回溯信息
      pytest -o faulthandler_timeout=X //命令行配置超时时间
      pytest --disable-warnings //命令行选项来阻止,告警信息的显示(有捕获告警只是不显示)
      pytest -p no:warnings //命令行,直接禁止告警的捕获;

      pytest -q -s --collect-only test_params.py //collect-only仅显示测试ID,不执行用例(用来收集测试用例的名称)
      设置固件的测试ID:使用ids @pytest.fixture(params=[0, 1], ids=['spam', 'ham']),也可以用一个函数来动态生成测试ID@pytest.fixture(params=[0, 1], ids=fun());
      同理也可以设置用例的测试ID:@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None) 参数化时ids是每个测试的实例的测试ID,报告可以记录,默认值是每一个实例的argvalue_拼接,如上是1_2;手动定义时ids值长度必须和argvalue长度保持一致;默认所有的id都进行了ascii编码,可以在pytest.ini中禁用ascii编码
      (disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True)
    • 执行
      1
      2
      3
      4
      5
      6
      7
      8
      9
      pytest ::							//执行指定的模块方法/类
      pytest path //执行指定路径及子路径下的所有以test开头或结尾的模块中,以test开头或结尾的方法/类
      pytest -k //模糊匹配要执行的用例
      pytest -m //执行指定标记用例

      pytest -x //pytest遇到第一个失败时退出执行
      pytest --maxfail==2 //设定允许失败的最大次数
      pytest -p mypluginmodule //-p尽早加载插件,插件可以是本地的插件,也可以是公共插件
      pytest -p no:doctest //加no提前阻止插件的加载
    • 结果
      1
      2
      3
      pytest --junitxml=path  		//在path路径生成一个xml格式的测试报告
      junit_suite_name = 节点名 //(pytest.ini中)自定义XML文件中testsuite根节点的名称
      junit_duration_report = call //(pytest.ini)报告只记录测试用例时间,不含前后置时间,默认time属性是含所有时间的

固件-前后置处理

固件的作用是提供了一个固定的基线,能重复的运行;固件装饰器(@pytest.fixture)的作用是注册一个固件,测试用例可以通过显示调用的方式使用固件(固件作为入参),调用的是固件的形参,实际生效的是固件的返回对象作为入参;默认可以不调用固件,因为固件默认配置了自动调用

  • 作用:固件的作用主要是进行用例的前后置处理
    固件根本作用域的不同,可以分别针对session/包/模块/类/方法进行前后置处理

  • 前后置处理

    • 实现示例:前后置处理有三种实现方式:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      #前后置处理方法1-yield
      @pytest.fixture()
      def smtp_connection_yield():
      smtp_connection = smtplib.SMTP("smtp.163.com", 25, timeout=5)
      yield smtp_connection
      print("关闭SMTP连接")
      smtp_connection.close()

      #前后置处理方法2-利用上下文自动关闭对象
      @pytest.fixture()
      def smtp_connection_yield():
      with smtplib.SMTP("smtp.163.com", 25, timeout=5) as smtp_connection:
      yield smtp_connection

      #利用注册的方式,来注册后置处理
      @pytest.fixture()
      def smtp_connection_fin(request):
      smtp_connection = smtplib.SMTP("smtp.163.com", 25, timeout=5)

      def fin():
      smtp_connection.close()

      request.addfinalizer(fin)
      return smtp_connection

      //(这个后置操作,只能对前置产生的实例对象生效)
  • 固件的使用

    • 放置位置: 固件一般是放置在conftest.py模块中统一维护;当然也可以在用例模块中定义固件;固件是支持显示调用(作为测试用例的入参)和自动调用的(默认就支持@pytest.fixture(autouse=True)autouse=True可省略)
    • 作用域
      固件一般放置在conftest.py模块中,而此模块一般放置根目录/功能目录的顶层(可以放置多个此模块,按就近原则生效,也就是在用例当前目录找到固件后就不去上一级查找);可以为每个固件定义作用域,定义完后,固件分别在作用域的范围内执行,默认的作用域是@pytest.fixture(scope='function'),作用域主要决定的是执行次数和执行顺序

    支持的作用域有:@pytest.fixture(scope=’function/class/module/session/package’,autouse=True)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @pytest.fixture(scope='function')			//每个用例方法都执行一遍固件的前后置处理
    @pytest.fixture(scope='class') //每个用例类仅执行一遍固件的前后置处理
    @pytest.fixture(scope='module') //每个模块仅执行一遍固件的前后置处理
    @pytest.fixture(scope='session') //每个会话对象仅执行一遍固件的前后置处理
    @pytest.fixture(scope='package') //每个包仅执行一遍固件的前后置处理

    类显示的调用固件:@pytest.mark.usefixtures('固件名','第二个固件'),此装饰器也可以给fun使用;
    模块显示的调用固件:test=pytest.mark.usefixtures("transact")

    可以使用固件来生成工厂函数,从而实现模块化,和函数定制(此时固件是可以接受参数的);

    固件可以进行参数化:如下,固件进行参数化后会创建多个实例,因此使用这些实例的测试用例也会执行多次
    @pytest.fixture(params=[('3+5', 8),pytest.param(('6*9', 42),
    marks=pytest.mark.xfail,id='failed')])
    如果不想执行多次,可以使用模糊匹配来匹配具体到具体的实例: pytest -k 163 用例 //固件进行参数化时,一定是一个实例执行完后(含前后置处理,才开始新的实例工作)
    //同上固件可以打标记,配置测试ID;使用参数化装饰器等价的方法如下:
    @pytest.mark.parametrize('test_input, expected',[('3+5', 8),
    pytest.param('6*9', 42, marks=pytest.mark.xfail,id='failed')])
    //给固件重命名后,原来的名字不可用,只能使用新的名称来显示的调用固件:@pytest.fixture(name="my_fixture_alias")
    用例按条件执行固件:@pytest.mark.parametrize("condition", [True, False])
    //复写操作,除了在conftest中,用例模块中,还可以在用例的参数化中进行复写(不做特殊配置时,参数名会覆盖同名固件)
    @pytest.mark.parametrize('已定义固件名', ['directly-overridden-username'])

    每个用例可以执行多个固件;执行顺序是显示调用优先级>自动调用;按作用域大小来,作用域越大越优先;作用域相同时,按从上到下的顺序来,不过,固件中参数是固件时调用的固件要优先执行;查找固件的顺序则按就近原则;
    • pytest内置的固件
      1
      2
      3
      4
      5
      6
      7
      8
      pytest有现成的一些固件,可以直接在测试用例中调用,或者在自定义的固件中调用;
      查看现成的固件的方法:pytest -q -v --fixtures;
      在程序执行时,动态的修改对象(使用固件monkeypatch);这种修改是临时性的,不改本地代码;
      创建临时文件/目录,(使用tmp_path);
      在测试用例中访问捕获信息(即标准输出/标准错误):可以使用固件capsys、capfd、capsysbinary
      capsys捕获的是系统级别,如capsys.readouterr()结果是个系统级别的标准输出和标准错误的元组
      capfd捕获的是文件/接口级别,如capfd.readouterr()结果是个接口级别的标准输出和标准错误的元组
      capsysbinary用来返回非文本型的数据,capsysbinary.readouterr()返回的是字节流
  • 特殊场景-文档测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    文档测试/注释测试;pytest会自动收集所有名称匹配test*.txt规则的文件,并调用doctest执行它们;注释中的代码的执行使用的是Python的标准库doctest模块来实现的;
    注释需要满足几个条件:
    ①文件名称是以test开头或结尾的Python文件;
    ②文档字符串中的注释必须是类似python交互式会话形式的注释(>>> something())
    //可以通过pytest --doctest-glob='*.rst'来扩展支持的文档格式
    //执行文档中的注释代码,必须要加选项pytest --doctest-modules命令行选项;也可以在pytest.ini文件中配置指定必须要文档测试[pytest]
    addopts = --doctest-modules
    //用pytest --doctest-continue-on-failure选项在文档测试遇到第一个失败后继续执行
    //可以定制文档测试失败后的,失败输出格式pytest --doctest-modules --doctest-report none/udiff/cdiff/ndiff
    通过在文档中添加''''>>> tmp = getfixture('tmpdir')'''的方式在文档中使用固件;通过doctest_namespace 固件定义的参数,可以在文档中直接使用

    使用pytest.skip(‘注释’),直接跳过文档测试,默认不执行文档测试

用例:(断言+异常处理+跳过+标记)

断言

  • 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #常规断言
    def test_
    assert True //如果判断条件的结果为True则断言成功;

    #指定预期异常
    def test_mytest():
    with pytest.raises(SystemExit) as excinfo:
    f() //若用例没抛出指定异常则断言失败,且必须是上下文中的最后一行,因为raises之后的不会被执行
    assert '456' in str(excinfo.value) //excinfo是上下文的实例,且在上下文环境中

    #可以给异常加标记
    @pytest.mark.xfail(raises=IndexError) //可以给异常加标记,出现IndexError,则标记用例失败类型为xfail,这种用法一般用来标记未修复的bug
    def test_f():
    f()
    除了断言还可以设置断点:使用pdb.set_trace(),只影响断点用例;

异常的结果

  • 不同数据类型的断言,不同地方都会标记出来;
  • 可以给断言失败,添加说明,可以用运算重载符,出现系统提示的字符串异常时,重载为我们想要的内容;第二种是利用钩子pytest_assertrepr_compare,来自定义异常;
  • 断言的异常信息,会存储在本地,如需禁止可以在conftest.py文件中加入这些配置实现:
    1
    2
    import sys
    sys.dont_write_bytecode = True
  • 关闭断言的失败提示功能:有两种方式(基本不会关闭)
    • 在需要关闭提示的模块的docstring中添加PYTEST_DONT_REWRITE字符串;
    • 执行pytest时,添加–assert=plain选项

异常处理

1
2
3
4
5
6
7
8
9
10
11
warning告警,可以手动通过warnings.warn方法来触发特定的告警;
recwarn fixture的功能和pytest.warning()等价;
可以通过命令行 pytest -W arg(action:message:category:module:lineno)方式来执行,从而自定义捕获的告警;
等价行为是通过pytest.ini配置文件来配置filterwarnings项(用来自定义过滤,也可以配置不捕获);等价的装饰器为@pytest.mark.filterwarnings;
--disable-warnings命令行选项来阻止,告警信息的显示(有捕获告警只是不显示);
-p no:warnings命令行,直接禁止告警的捕获;
等价的使用pytest.deprecated_call方法来调用告警对象,也会实现禁止捕获告警;
assert pytest.warns((DeprecationWarning, PendingDeprecationWarning), api_call_v1, match=r'和 pytest.raises() 方法一样,这时 pytest 不再判断告警信息是否正确') == 200
来通过匹配告警,这个操作是匹配到的告警不显示,同时进行断言;

异常提示:pytest.fail('期望 api_call_v1 触发一个告警,实际上没有;')用来触发异常提示;

标记

使用标记来给用例打上不同的标记,从而在结果收集时,实现对用例的区分;

  • 查看用例标记:
    使用 pytest -r来定制显示不同标记的用例;支持的标记有 (f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed, (p)assed, (P)assed with output, (a)ll except passed(p/P), or (A)ll
  • @pytest.mark.xfail()用来标记预期是失败的用例,如果满足预期的失败,则结果为xfail,如果是成功,则结果一般是xpass,可能是FAILED,详情如下

alt text

  • 标记可以和参数化装饰器结合,他提供了一个方法 pytest.param,可以给每个参数对应的实例打一个标记,并给一个测试id
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @pytest.mark.parametrize(
    ('n', 'expected'),
    [(2, 1),
    pytest.param(2, 1, marks=pytest.mark.xfail(), id='XPASS'),
    pytest.param(0, 1, marks=pytest.mark.xfail(raises=ZeroDivisionError), id='XFAIL'),
    pytest.param(1, 2, marks=pytest.mark.skip(reason='无效的参数,跳过执行')),
    pytest.param(1, 2, marks=pytest.mark.skipif(sys.version_info <= (3, 8), reason='请使用3.8及以上版本的python。'))])
    def test_params(n, expected):
    assert 2 / n == expected

跳过

跳过用例的方法总结如下:
alt text
其中@pytest.mark.skipif //如果一个用例有多个条件跳过装饰器,满足任意一个即跳过; @pytest.importorskip装饰器是会先进行import模块操作,同时会判断模块的版本;如果版本不对,或import失败则跳过;

参数化

固件的参数化

1
2
使用@pytest.fixture(params=[('3+5', 8),pytest.param(('6*9', 42),
marks=pytest.mark.xfail,id='failed')]);和pytest.mark.parametrize装饰器是等价的

测试用例参数化

参数化是指对用例的参数传递不同的值,来执行多次,从而覆盖用例不同的场景(不同值)

  • 对象
    • 可以对测试用例方法进行参数化
    • 可以对测试类进行参数化
    • 可以对模块进行参数化:pytestmark = pytest.mark.parametrize('test_input, expected', [(1, 2), (3, 4)])后续的用例直接调用参数即可
  • 方法:@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
    • argnames:参数名必须是用例引入的参数的子集(fun(arg1,arg2),必须是这两个参数的子集);且引入的参数必须是没有默认值的;结构可以是用逗号分隔的字符串,或者一个列表/元组; 参数名默认会覆盖同名的固件;
    • argvalues:实际返回的是一个命名元祖,ParameterSet(values=(1, 2), marks=[], id=None)];可以不带标记和测试id,也可以带;结构上必须是一个可迭代对象可以是[(1, 2), [2, 3], set([3, 4])]/方法返回的可迭代对象; 如果argvalue要带标记和测试ID,可以这样实现:pytest.param(2, 1, marks=pytest.mark.xfail(), id='XPASS')param方法实际是对命名元祖的封装;
    • indirect参数:有默认值,为TRUE表示参数名不覆盖同名固件,且参数值要传递给固件,最后固件的返回才是实参@pytest.mark.parametrize('min, max', [(1, 2), (3, 4)], indirect=True/['max']) //['max']仅指定这个参数名不覆盖固件
    • ids:ids是每个测试的实例的测试ID,报告可以记录,默认值是每一个实例的argvalue_拼接,如上是1_2;手动定义时ids值长度必须和argvalue长度保持一致;默认所有的id都进行了ascii编码,可以在pytest.ini中禁用ascii编码(disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True) 可以构造函数方法来使用每个的argvalue参数来生成ids,类似ids=fun()
    • scope:scope定义的是argnames的作用域,并通过argvalues的实例划分测试用例,影响到测试用例的收集顺序(不同用例,相同参数时,会根据值的大小来划分收集顺序;如果参数是固件时,且不覆盖,则参数的作用域,就是固件的作用域,按这个顺序收集测试结果,默认是function级别)
    • 特殊情况:
      1
      2
      3
      4
      5
      如果参数化没传值时,实例的结果将会被设置为SKIPPED;
      这种情况可以在pytest.ini中设置empty_parameter_set_mark选项来改变这种行为,可以的值如下:
      skip:默认值
      xfail:执行跳过直接将示例标记为XFAIL,等价于xfail(run=False)
      fail_at_collect:上报一个CollectError异常;
      一个用例上可以有多个参数化标记,执行顺序是从近到远,组合提供值
      @pytest.mark.parametrize(‘test_input’, [1, 2, 3])
      @pytest.mark.parametrize(‘test_output, expected’, [(1, 2), (3, 4)])
      结果:1_2_1,1_2_2,1_2_3,3_4_1,…

定制报告

为测试报告中的测试用例添加额外的信息,使用record_property fixture

1
2
3
4
5
6
7
8
9
10
def test_record_property(record_property):
record_property("test_id额外信息", 10010额外信息值)
assert 1
也可以在测试报告中加入用例的标记信息 //修改pytest_collection_modifyitems钩子方法,添加对test_id标记的支持;
可以为测试报告添加用例额外的属性信息 //使用record_xml_attribute fixture
可以在测试报告中为整个测试集添加额外的信息;

可以在报告中为用例创建链接
pytest --pastebin=all //为所有用例创建链接
pytest --pastebin=failed //为失败用例创建链接

其他的对测试报告的定制操作,见上方选项合集

性能-缓存

  • 是什么:pytest执行时默认会在根目录生成一个.pytest_cache文件夹,用来记录执行的情况,主要记录执行的所有失败(lastfailed)、执行的所有实例(nodeids)、最近一次失败(stepwise)、缓存配置数据();缓存是通过pytest自带的cacheprovider插件来实现;

  • 作用:可以通过选项来依赖缓存的结果和配置数据来定制执行的顺序、和跳过某些用例、使用缓存配置数据,从而提高性能;

  • 怎么样:生成缓存文件-控制执行顺序(范围);

    • 缓存文件:默认位置是根目录生成一个.pytest_cache文件夹;可以通过pytest.ini中配置cache_dir = .pytest-cache来自定义缓存文件夹路径,可配置相对和绝对路径;
    • 缓存中主要起作用的是lastfailed(所有失败实例)/nodeids(所有实例)/stepwise(最近失败实例)

│ └───.pytest-cache
│ │ .gitignore
│ │ CACHEDIR.TAG
│ │ README.md
│ │
│ └───v
│ └───cache
│ lastfailed
│ nodeids
│ stepwise

  • 控制执行顺序(范围):通过一些选项来利用上面的文件控制实例的执行顺序,并且过滤一些实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    查看缓存:pytest src/chapter-12/ -q --cache-show 'lastfailed'/'nodeids'/'stepwise'
    pytest --lf --collect-only src/chapter-12/ //仅执行已经收集到的失败实例
    pytest --collect-only -s --ff src/chapter-12/ //先执行上次收集到的失败实例,在执行其他
    pytest --collect-only -s --nf src/chapter-12/ //先执行新添加的-继而执行修改的(按最晚修改最先执行)-最后执行其他实例;
    pytest --cache-clear -q -s src/chapter-12/test_pass.py //先删除缓存文件夹(pytest-cache),在创建缓存文件夹,保存最新的缓存数据

    //以下都用于之前没有采集到失败实例的场景
    pytest -q -s --ff --lfnf none src/chapter-12/test_pass.py //会忽略失败

    pytest -q -s --ff --lfnf all src/chapter-12/test_pass.py //遇到失败就结束了,只保留之前的成功的

    #缓存配置数据
    @pytest.fixture
    def mydata(request):
    val = request.config.cache.get("example/value", None) //读取缓存配置
    if val is None:
    expensive_computation()
    val = 42
    #设置缓存配置。没有文件时,会先创建在设置,已存在会覆盖旧的
    request.config.cache.set("example/value", val)
    return val

    stepwise文件用来记录最近一次的失败;可以指定从这个失败开始执行,用此选项调度一般遇到失败pytest就会结束执行如下:
    pytest --cache-clear --sw -q src/chapter-12/test_sample.py
    //--cache-clear见上方删除旧缓存,--sw是(stepwise缩写),此选项执行时,遇到失败就会结束整个pytest,并将这个失败记录到stepwise文件;如果不指定--sw选项,这个文件不记录数据;下次在也--sw选项执行时,会优先执行stepwise文件中记录的实例,当遇到下一个失败时才结束,并且会使用新的失败来覆盖这个文件;
    pytest --sw --stepwise-skip -q src/chapter-12/test_sample.py //跳过这个失败,继续执行后面的,遇到后续的失败在结束;

pytest-概要版
官方文档-中文版

欢迎关注我的其它发布渠道