Tre*_*vor 23 python testing unit-testing global-variables pytest
我有py.test运行的多个测试,它们位于多个文件的多个类中.
共享一个大字典的最简单的方法是什么 - 我不想复制 - py.test使用的每个文件中每个类的每个方法?
简而言之,我需要为每个测试制作一个"全局变量".在py.test之外,我没有使用这个变量,所以我不想将它存储在被测试的文件中.我经常使用py.test的灯具,但这似乎有点过分了.也许这是唯一的方法?
flu*_*lub 17
更新:不推荐使用pytest-namespace hook.不使用.有关详细信息,请参阅#3735.
你提到了明显且最不神奇的选择:使用夹具.您可以pytestmark = pytest.mark.usefixtures('big_dict')在模块中使用它来应用于整个模块,但它不会在您的命名空间中,因此明确请求它可能是最好的.
或者,您可以使用钩子将内容分配到pytest命名空间:
# conftest.py
def pytest_namespace():
return {'my_big_dict': {'foo': 'bar'}}
Run Code Online (Sandbox Code Playgroud)
现在你有了pytest.my_big_dict.夹具可能仍然更好.
use*_*458 13
我喜欢py.test有很多东西,但我绝对讨厌的一件事是代码智能工具有多糟糕.我不同意在这种情况下声明变量的autouse fixture 是"最清晰"的方法,因为它不仅完全阻碍了我的linter,而且还有其他任何不熟悉py.test如何工作的人.那里有很多魔法,imo.
所以,你能做的一件事就是不要让你的linter爆炸并且不需要TestCase样板来创建一个名为globals的模块.在此模块中,将您想要全局的内容的名称存根到{}或None,并将全局模块导入到测试中.然后在conftest.py文件中,使用py.test钩子根据需要设置(或重置)全局变量.这样做的好处是可以在构建测试时为您提供存根,并在运行时为测试提供完整数据.
例如,你可以使用pytest_configure()钩子在py.test启动时设置你的dict.或者,如果您想确保每次测试之间的数据都是原始的,您可以在每次测试之前使用夹具将全局变量分配给已知状态.
# globals.py
my_data = {} # Create a stub for your variable
# test_module.py
import globals as gbl
def test_foo():
assert gbl.my_data['foo'] == 'bar' # The global is in the namespace when creating tests
# conftest.py
import globals as gbl
my_data = {'foo': 'bar'} # Create the master copy in conftest
@pytest.fixture(autouse=True)
def populate_globals():
gbl.my_data = my_data # Assign the master value to the global before each test
Run Code Online (Sandbox Code Playgroud)
这种方法的另一个优点是你可以在你的全局模块中使用类型提示来为你的测试中的全局对象提供代码完成,这对于dict来说可能不是必需的,但是当我使用一个对象时我发现它很方便(比如webdriver).:)
拥有一个大型的全局字典,每个测试都使用它可能是一个坏主意.如果可能的话,我建议重构你的测试以避免这种情况.
也就是说,我就是这样做的:定义一个autouse fixture,它在每个函数的全局命名空间中添加对字典的引用.
这是一些代码.它们都在同一个文件中,但您可以将夹具移到conftest.py测试的顶层.
import pytest
my_big_global = {'key': 'value'}
@pytest.fixture(autouse=True)
def myglobal(request):
request.function.func_globals['foo'] = my_big_global
def test_foo():
assert foo['key'] == 'value'
def test_bar():
assert foo['key'] == 'bar'
Run Code Online (Sandbox Code Playgroud)
这是我运行此代码时的输出:
$ py.test test_global.py -vv
======================================= test session starts =======================================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 2 items
test_global.py:9: test_foo PASSED
test_global.py:12: test_bar FAILED
============================================ FAILURES =============================================
____________________________________________ test_bar _____________________________________________
def test_bar():
> assert foo['key'] == 'bar'
E assert 'value' == 'bar'
E - value
E + bar
test_global.py:13: AssertionError
=============================== 1 failed, 1 passed in 0.01 seconds ===============================
Run Code Online (Sandbox Code Playgroud)
请注意,您不能使用会话范围的装置,因为您无权访问每个功能对象.因此,我确保一次定义我的大型全局字典并使用对它的引用 - 如果我在该赋值语句中定义了字典,则每次都会生成一个新的副本.
最后,做这样的事情可能是一个坏主意.祝你好运:)
我很惊讶没有提到缓存的答案:从版本2.8开始,pytest它具有强大的缓存机制.
@pytest.fixture(autouse=True)
def init_cache(request):
data = request.config.cache.get('my_data', None)
data = {'spam': 'eggs'}
request.config.cache.set('my_data', data)
Run Code Online (Sandbox Code Playgroud)
通过内置request夹具访问测试中的数据字典:
def test_spam(request):
data = request.config.cache.get('my_data')
assert data['spam'] == 'eggs'
Run Code Online (Sandbox Code Playgroud)
很酷的request.cache是它存在于磁盘上,所以它甚至可以在测试运行之间共享.当你运行测试distributed(pytest-xdist)或者有一些长时间运行的数据生成时,这很方便,一旦生成就不会改变:
@pytest.fixture(autouse=True)
def generate_data(request):
data = request.config.cache.get('my_data', None)
if data is None:
data = long_running_generation_function()
request.config.cache.set('my_data', data)
Run Code Online (Sandbox Code Playgroud)
现在,除非您明确清除磁盘上的缓存,否则测试不需要重新计算不同测试运行的值.看一下缓存中当前的内容:
$ pytest --cache-show
...
my_data contains:
{'spam': 'eggs'}
Run Code Online (Sandbox Code Playgroud)
使用--cache-clear标志重新运行测试以删除缓存并强制重新计算数据.或者只删除.pytest_cache项目根目录中的目录.
pytest文档中的相关部分:缓存:使用跨testrun状态.
| 归档时间: |
|
| 查看次数: |
26790 次 |
| 最近记录: |