Pytest权威教程14-缓存:使用跨执行状态
缓存:使用跨执行状态
版本2.8中的新函数。
使用方法
该插件提供了两个命令行选项,用于重新运行上次pytest
调用的失败:
--lf
,--last-failed
- 只重新运行故障。--ff
,--failed-first
- 先运行故障然后再运行其余的测试。
对于清理(通常不需要),--cache-clear
选项允许在测试运行之前删除所有跨会话缓存内容。
其他插件可以访问[config.cache对象以在调用之间设置/获取json可编码值pytest
。
注意
此插件默认启用,但如果需要可以禁用:请参阅[按名称取消激活/取消注册插件(此插件的内部名称为cacheprovider
)。
首先只重新运行故障或故障
首先,让我们创建50个测试调用,其中只有2个失败:
# content of test_50.py
import pytest
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
pytest.fail("bad luck")
如果你是第一次运行它,你会看到两个失败:
$ pytest -q
.................F.......F........................ [100%]
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
2 failed,48 passed in 0.12 seconds
如果你然后运行它--lf
:
$ pytest --lf
=========================== test session starts ============================
platform linux -- Python 3.x.y,pytest-4.x.y,py-1.x.y,pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 50 items / 48 deselected / 2 selected
run-last-failure: rerun previous 2 failures
test_50.py FF [100%]
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
================= 2 failed,48 deselected in 0.12 seconds ==================
你只运行了上次运行中的两个失败测试,而尚未运行48个测试(“取消选择”)。
现在,如果使用该--ff
选项运行,将运行所有测试,但首先执行先前的失败(从一系列FF
和点中可以看出):
$ pytest --ff
=========================== test session starts ============================
platform linux -- Python 3.x.y,pytest-4.x.y,py-1.x.y,pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 50 items
run-last-failure: rerun previous 2 failures first
test_50.py FF................................................ [100%]
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i",range(50))
def test_num(i):
if i in (17,25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:6: Failed
=================== 2 failed,48 passed in 0.12 seconds ====================
新的--nf
,--new-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
新的config.cache对象
插件或conftest.py支持代码可以使用pytestconfig
对象获取缓存值。这是一个实现[pytest fixture的基本示例插件[:显式,模块化,可伸缩,它在pytest调用中重用以前创建的状态:
# content of test_caching.py
import pytest
import time
def expensive_computation():
print("running expensive computation...")
@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
def test_function(mydata):
assert mydata == 23
如果你是第一次运行此命令,则可以看到print语句:
$ pytest -q
F [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
test_caching.py:17: AssertionError
-------------------------- Captured stdout setup ---------------------------
running expensive computation...
1 failed in 0.12 seconds
如果再次运行它,将从缓存中检索该值,并且不会打印任何内容:
$ pytest -q
F [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
test_caching.py:17: AssertionError
1 failed in 0.12 seconds
有关更多详细信息,请参阅[config.cache。
检查缓存内容
你始终可以使用--cache-show
命令行选项查看缓存的内容:
$ pytest --cache-show
=========================== test session starts ============================
platform linux -- Python 3.x.y,pytest-4.x.y,py-1.x.y,pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
cachedir: $PYTHON_PREFIX/.pytest_cache
------------------------------- cache values -------------------------------
cache/lastfailed contains:
{'test_50.py::test_num[17]': True,
'test_50.py::test_num[25]': True,
'test_assert1.py::test_function': True,
'test_assert2.py::test_set_comparison': True,
'test_caching.py::test_function': True,
'test_foocompare.py::test_compare': True}
cache/nodeids contains:
['test_caching.py::test_function']
cache/stepwise contains:
[]
example/value contains:
42
======================= no tests ran in 0.12 seconds =======================
清除缓存内容
你可以通过添加如下--cache-clear
选项来指示pytest清除所有缓存文件和值:
pytest --cache-clear
对于Continuous Integration服务器的调用,建议使用此选项,其中隔离和正确性比速度更重要。
逐步修复失败用例
作为替代方案,尤其是对于你希望测试套件的大部分都会失败的情况,允许你一次修复一个。测试套件将运行直到第一次失败然后停止。在下次调用时,测试将从上次失败测试继续,然后运行直到下一次失败测试。你可以使用该选项忽略一个失败的测试,并在第二个失败的测试中停止测试执行。如果你遇到失败的测试而只是想稍后忽略它,这将非常有用。--lf-x``--sw``--stepwise``--stepwise-skip
unittest.TestCase支持
Pytest
支持unittest
开箱即用的基于Python的测试。它旨在利用现有unittest
的测试套件将pytest用作测试运行器,并允许逐步调整测试套件以充分利用pytest的函数。
要使用运行现有unittest
样式的测试套件pytest
,请键入:
pytest tests
pytest将自动收集unittest.TestCase
子类及其test
方法test_*.py
或*_test.py
文件。
几乎所有unittest
函数都受支持:
@unittest.skip
风格装饰;setUp/tearDown
;setUpClass/tearDownClass
;setUpModule/tearDownModule
;
到目前为止,pytest不支持以下函数:
- load_tests协议;
- 分测验;
开箱即用的好处
通过使用pytest运行测试套件,你可以使用多种函数,在大多数情况下无需修改现有代码:
- 获得[更多信息性的追溯;
- stdout和stderr捕获;
- ;
- 在第一次(或N次)故障后停止;
- -pdb);
- 使用[pytest-xdist插件将测试分发给多个CPU;
- 使用[普通的assert-statements对此非常有帮助);
unittest.TestCase子类中的pytest特性
以下pytest函数适用于unittest.TestCase
子类:
- 标记: skip,[skipif,[xfail;
- 自动使用Fixture方法;
下面pytest函数不工作,也许永远也因不同的设计理念:
- Fixture方法);
- 参数化;
- 定制挂钩;
第三方插件可能运行也可能不运行,具体取决于插件和测试套件。
unittest.TestCase 使用标记将pytestFixture方法混合到子类中
运行unittestpytest
允许你使用其[Fixture方法机制进行unittest.TestCase
样式测试。假设你至少浏览了pytest fixture函数,让我们跳转到一个集成pytestdb_class
fixture,设置类缓存数据库对象,然后从unittest样式测试中引用它的示例如:
# content of conftest.py
# we define a fixture function below and it will be "used" by
# referencing its name from tests
import pytest
@pytest.fixture(scope="class")
def db_class(request):
class DummyDB(object):
pass
# set a class attribute on the invoking test context
request.cls.db = DummyDB()
这定义了一个fixture函数db_class
- 如果使用的话 - 为每个测试类调用一次,并将class-leveldb
属性设置为一个DummyDB
实例。fixture函数通过接收一个特殊request
对象来实现这一点,该对象允许访问[请求测试上下文,例如cls
属性,表示使用该fixture的类。该架构将Fixture方法写入与实际测试代码分离,并允许通过最小参考(Fixture方法名称)重新使用Fixture方法。那么让unittest.TestCase
我们使用fixture定义编写一个实际的类:
# content of test_unittest_db.py
import unittest
import pytest
@pytest.mark.usefixtures("db_class")
class MyTest(unittest.TestCase):
def test_method1(self):
assert hasattr(self,"db")
assert 0,self.db # fail for demo purposes
def test_method2(self):
assert 0,self.db # fail for demo purposes
在@pytest.mark.usefixtures("db_class")
类的装饰可确保pytest固定函数db_class
被调用每一次班。由于故意失败的断言语句,我们可以看看self.db
回溯中的值:
$ pytest test_unittest_db.py
=========================== test session starts ============================
platform linux -- Python 3.x.y,pytest-4.x.y,py-1.x.y,pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 2 items
test_unittest_db.py FF [100%]
================================= FAILURES =================================
___________________________ MyTest.test_method1 ____________________________
self = <test_unittest_db.MyTest testMethod=test_method1>
def test_method1(self):
assert hasattr(self,"db")
> assert 0,self.db # fail for demo purposes
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0xdeadbeef>
E assert 0
test_unittest_db.py:9: AssertionError
___________________________ MyTest.test_method2 ____________________________
self = <test_unittest_db.MyTest testMethod=test_method2>
def test_method2(self):
> assert 0,self.db # fail for demo purposes
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0xdeadbeef>
E assert 0
test_unittest_db.py:12: AssertionError
========================= 2 failed in 0.12 seconds =========================
这个默认的pytest回溯显示两个测试用例共享同一个self.db
实例,这是我们在编写上面的类范围的fixture函数时的意图。
使用autouseFixture方法和访问其他Fixture方法
虽然通常更好地明确声明对给定测试需要使用的Fixture方法,但有时你可能想要在给定的上下文中自动使用Fixture方法。毕竟,传统的unittest-setup风格要求使用这种隐含的Fixture方法编写,而且很有可能,你习惯它或者喜欢它。
你可以使用标记Fixture方法函数@pytest.fixture(autouse=True)
并在要使用它的上下文中定义Fixture方法函数。让我们看一个initdir
Fixture方法,它使一个TestCase
类的所有测试用例都在一个预先初始化的临时目录中执行samplefile.ini
。我们的initdir
fixture本身使用pytest builtin[tmpdirfixture来委托创建一个per-test临时目录:
# content of test_unittest_cleandir.py
import pytest
import unittest
class MyTest(unittest.TestCase):
@pytest.fixture(autouse=True)
def initdir(self,tmpdir):
tmpdir.chdir() # change to pytest-provided temporary directory
tmpdir.join("samplefile.ini").write("# testdata")
def test_method(self):
with open("samplefile.ini") as f:
s = f.read()
assert "testdata" in s
由于该autouse
标志,initdir
fixture函数将用于定义它的类的所有方法。这是@pytest.mark.usefixtures("initdir")
在类中使用标记的快捷方式,如上例所示。
运行此测试模块......:
$ pytest -q test_unittest_cleandir.py
. [100%]
1 passed in 0.12 seconds
...给我们一个通过测试,因为initdir
Fixture方法函数在之前执行test_method
。
注意
unittest.TestCase
方法不能直接接收fixture参数作为实现可能会导致运行通用unittest.TestCase测试套件的能力。
以上usefixtures
和autouse
示例应该有助于将pytestFixture方法混合到unittest套件中。
你也可以逐步从子类化转移unittest.TestCase
到普通断言,然后开始逐步从完整的pytest函数集中受益。
注意
从unittest.TestCase
子类运行测试--pdb
将禁用针对发生异常的情况的tearDown和cleanup方法。这允许对所有在其tearDown机器中具有重要逻辑的应用程序进行适当的事后调试。但是,支持此函数会产生以下副作用:如果人们覆盖unittest.TestCase``__call__
或者run
需要以debug
相同的方式覆盖(对于标准unittest也是如此)。
注意
由于两个框架之间的架构差异,在unittest
测试call
阶段而不是在pytest
标准setup
和teardown
阶段中执行基于测试的设置和拆卸。在某些情况下,这一点非常重要,特别是在推理错误时。例如,如果unittest
基于a的套件在设置期间出现错误,pytest
则在其setup
阶段期间将报告没有错误,并且将在此期间引发错误call
。
Pytest权威教程14-缓存:使用跨执行状态的更多相关文章
- Pytest权威教程(官方教程翻译)
Pytest权威教程01-安装及入门 Pytest权威教程02-Pytest 使用及调用方法 Pytest权威教程03-原有TestSuite的执行方法 Pytest权威教程04-断言的编写和报告 P ...
- Pytest权威教程21-API参考-03-夹具(Fixtures)
目录 夹具(Fixtures) @ pytest.fixture config.cache的 capsys capsysbinary capfd capfdbinary doctest_namespa ...
- Pytest权威教程25-配置
目录 配置 命令行选项和配置文件设置 初始化:确定ROOTDIR和INIFILE 寻找rootdir 如何更改命令行选项默认值 内置的配置文件选项 返回: Pytest权威教程 配置 命令行选项和配置 ...
- Pytest权威教程21-API参考-07-配置选项(Configuration Options)
目录 配置选项(Configuration Options) addopts cache_dir confcutdir console_output_style doctest_encoding do ...
- Pytest权威教程21-API参考-04-钩子(Hooks)
目录 钩子(Hooks) 引导时的Hook方法 初始化时的Hook方法 测试运行时的Hook方法 收集用例时的Hook方法 生成测试结果时的Hook方法 调试/交互Hook方法 返回: Pytest权 ...
- Pytest权威教程02-Pytest 使用及调用方法
目录 Pytest 使用及调用方法 使用python -m pytest调用pytest 可能出现的执行退出code 获取版本路径.命令行选项及环境变量相关帮助 第1(N)次失败后停止测试 指定及选择 ...
- Pytest权威教程05-Pytest fixtures:清晰 模块化 易扩展
目录 Pytest fixtures:清晰 模块化 易扩展 Fixtures作为函数参数使用 Fixtures: 依赖注入的主要例子 conftest.py: 共享fixture函数 共享测试数据 生 ...
- Pytest权威教程20-日志
目录 记录日志 caplog Fixture方法 实时日志 版本改动记录 Pytest3.4中不向后兼容的更改 返回: Pytest权威教程 记录日志 Pytest默认捕获WARNING以上日志消息, ...
- Pytest权威教程19-编写钩子(Hooks)方法函数
目录 编写钩子(Hooks)函数 钩子函数验证和执行 firstresult: 遇到第一个有效(非None)结果返回 hookwrapper:在其他钩子函数周围执行 钩子(Hooks)函数排序/调用示 ...
随机推荐
- NEST health与settings
/// <summary> /// 创建Idx,并设置分片和副本 /// </summary> public void Settings() { var response = ...
- 【洛谷 P3041】 [USACO12JAN]视频游戏的连击Video Game Combos(AC自动机,dp)
题目链接 手写一下AC自动机(我可没说我之前不是手写的) Trie上dp,每个点的贡献加上所有是他后缀的串的贡献,也就是这个点到根的fail链的和. #include <cstdio> # ...
- 深入理解JVM(四) -- 垃圾内存回收的判定方法和内容
上一篇文章我们学到了对象在内存中是如何存储的已经是如何被访问的,这篇文章将介绍当内存空间不够时,虚拟机将怎样判定对象可不可以被回收已经哪些地方会发生回收. 垃圾回收主要(不是全部)发生在堆内存中,当一 ...
- 有状态的bean和无状态的bean的区别
有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”:一旦用户灭亡(调用结束或实例结束),bean的生命期也告结束.即每个用户最初都会得到一个初 ...
- redis 异常 MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk
MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. 解决方 ...
- EhLib使用全攻略
使用 TDBSumList 组件 还记得以前有朋友问过这样一个问题:在 DBGrid 下如何像 Excel 一样能够做统计计算,实话说,使用 DBGrid 来做的话着实不易,不过现在有了这个咚咚, ...
- python(列表函数)
一.列表函数 1.sort()原址排序 参数默认reverse=False时为正序排序 list1 = [1,3,5,2,1,23,18] list1.sort() print (list1) 当参数 ...
- [openssl][nginx] 使用openssl模拟ssl/tls客户端测试nginx stream
一 server的配置 nginx # cat conf/nginx.conf daemon off; events { debug_connection ; } stream { upstream ...
- 【转】高性能网络编程3----TCP消息的接收
这篇文章将试图说明应用程序如何接收网络上发送过来的TCP消息流,由于篇幅所限,暂时忽略ACK报文的回复和接收窗口的滑动. 为了快速掌握本文所要表达的思想,我们可以带着以下问题阅读: 1.应用程序调用r ...
- Linux命令——watch
参考:Linux watch Command Tutorial for Beginners (5 Examples) 前言 有的时候我们想重复执行某一命令,通过该命令的输出进而获知系统某些信息.wat ...