我正在使用pytest为可在本地和云端运行的软件编写功能测试。我想创建2个模块,每个模块具有相同的模块/夹具名称,并且根据我在本地或在云中运行测试而具有pytest加载一个或另一个:
/fixtures
/fixtures/__init__.py
/fixtures/local_hybrids
/fixtures/local_hybrids/__init__.py
/fixtures/local_hybrids/foo.py
/fixtures/cloud_hybrids
/fixtures/cloud_hybrids/__init__.py
/fixtures/cloud_hybrids/foo.py
/test_hybrids/test_hybrids.py
foo.py
(两者都是):
import pytest
@pytest.fixture()
def my_fixture():
return True
/fixtures/__init__.py
:
if True:
import local_hybrids as hybrids
else:
import cloud_hybrids as hybrids
/test_hybrids/test_hybrids.py
:
from fixtures.hybrids.foo import my_fixture
def test_hybrid(my_fixture):
assert my_fixture
最后一个代码块当然不起作用,因为import fixtures.hybrids
正在查看文件系统而不是__init__.py
的“假”命名空间,这与from fixtures import hybrids
不同,这是有效的(但你不能使用灯具,因为名称将涉及点符号)。
我意识到我可以使用pytest_generate_test来动态改变灯具(也许?)但是我真的很讨厌在该函数中手动管理每个灯具......我希望动态导入(如果是x,导入这个,否则导入那个)是标准的Python,不幸的是它与fixtures机制发生了冲突:
import fixtures
def test(fixtures.hybrids.my_fixture): # of course it doesn't work :)
...
我还可以在init中依次导入每个fixture函数;更多的腿部工作,但仍然是一个可行的选择来欺骗pytest并获得没有点的夹具名称。
告诉我黑魔法。 :)可以吗?
答案 0 :(得分:1)
我认为在你的情况下最好定义一个夹具 - environment
或其他好名字。
这个fixture可以只是来自os.environ ['KEY']的getter,或者你可以添加自定义命令行参数,如here 然后像here一样使用它 最终用途为here。
我想说的是你需要将思维转换为依赖注入:一切都应该是一个固定装置。在您的情况下(以及我的插件中),运行时环境应该是一个夹具,在所有其他依赖于环境的夹具中进行检查。
答案 1 :(得分:0)
你可能在这里遗漏了一些东西:如果你想重新使用这些装置,你需要明确说出来:
from fixtures.hybrids.foo import my_fixture
@pytest.mark.usefixtures('my_fixture')
def test_hybrid(my_fixture):
assert my_fixture
在这种情况下,你可以调整pytest如下:
from local_hybrids import local_hybrids_fixture
from cloud_hybrids import cloud_hybrids_fixture
fixtures_to_test = {
"local":None,
"cloud":None
}
@pytest.mark.usefixtures("local_hybrids_fixture")
def test_add_local_fixture(local_hybrids_fixture):
fixtures_to_test["local"] = local_hybrids_fixture
@pytest.mark.usefixtures("cloud_hybrids_fixture")
def test_add_local_fixture(cloud_hybrids_fixture):
fixtures_to_test["cloud"] = cloud_hybrids_fixture
def test_on_fixtures():
if cloud_enabled:
fixture = fixtures_to_test["cloud"]
else:
fixture = fixtures_to_test["local"]
...
如果周围有更好的解决方案我也很感兴趣;)
答案 2 :(得分:0)
我真的不认为在python中有这样做的“好方法”,但仍然可以通过少量的黑客攻击。您可以使用您想要使用的灯具更新子文件夹的sys.path并直接导入灯具。在脏的情况下,它看起来像那样:
用于你的灯具/ __ init __。py:
if True:
import local as hybrids
else:
import cloud as hybrids
def update_path(module):
from sys import path
from os.path import join, pardir, abspath
mod_dir = abspath(join(module.__file__, pardir))
path.insert(0, mod_dir)
update_path(hybrids)
并在客户端代码(test_hybrids / test_hybrids.py)中:
import fixtures
from foo import spam
spam()
在其他情况下,您可以使用更复杂的操作从云/本地文件夹中直接将所有模块/包/函数等虚假移动到fixture的__init__.py中。不过,我认为 - 这不值得一试。
还有一件事 - 黑魔法不是最好用的,我建议你使用点缀符号“从Y导入X” - 这是更稳定的解决方案。