pytest 固定装置从外部范围重新定义名称 [pylint]

Posted

技术标签:

【中文标题】pytest 固定装置从外部范围重新定义名称 [pylint]【英文标题】:pytest fixtures Redefining name from outer scope [pylint] 【发布时间】:2018-02-15 18:52:36 【问题描述】:

我正在学习 pytest,并使用 pylint 对代码进行 lint。 但是pylint还是抱怨:W0621: Redefining name %r from outer scope (line %s)

以下示例来自 pytest:

# test_wallet.py

@pytest.fixture
def my_wallet():
    '''Returns a Wallet instance with a zero balance'''
    return Wallet()

@pytest.mark.parametrize("earned,spent,expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected

从外部范围重新定义名称my_wallet

我找到了将_ 前缀添加到灯具名称的解决方法:_my_wallet

如果我想将固定装置与函数保存在同一个文件中,最佳做法是什么?

    在所有灯具前加上_? 禁用此pylint 检查测试? 更好的建议?

【问题讨论】:

【参考方案1】:

pytest docs 为 @pytest.fixture 说这个:

如果在定义它的同一模块中使用了一个fixture,则 夹具的函数名称将被函数 arg 遮蔽 请求夹具;解决此问题的一种方法是命名装饰 函数fixture_<fixturename> 然后使用 @pytest.fixture(name='<fixturename>').

所以这个解决方案类似于你的选项 1,除了 pytest 作者建议为夹具函数提供一个更具描述性的名称。所以替换这两行

@pytest.fixture
def my_wallet():

与:

@pytest.fixture(name="my_wallet")
def fixture_my_wallet():

文档中的描述还暗示了另一种解决方案,即将固定装置移动到conftest.py,这样它们就与使用固定装置的测试代码不在同一个模块中。此位置对于在测试模块之间共享固定装置也很有用。

【讨论】:

这应该是有效的答案。 这里是相关pytest docs的更新链接 这行得通。但是如果你使用 mocker,你仍然会得到 pylint 错误。例如:from pytest_mock import mocker 后跟 def test_my_thing(mocker): 会给您一个 pylint 错误。我认为这就是为什么这么多人投票支持其他答案的原因,该答案建议对整个文件禁用此 pylint 规则。这很糟糕。在我看来,pylint 践踏了所有良好的 linting 规则。【参考方案2】:

我刚刚在我的测试文件中禁用了该规则:

# pylint: disable=redefined-outer-name
# ^^^ this
import pytest

@pytest.fixture
def my_wallet():
    '''Returns a Wallet instance with a zero balance'''
    return Wallet()

@pytest.mark.parametrize("earned,spent,expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected

【讨论】:

这很可悲。 lint 规则的存在是有充分理由的。我把这归咎于 pylint。【参考方案3】:

在def中添加fixture的name参数和fixture_前缀。

@pytest.fixture(name="my_wallet")
def fixture_wallet():
    '''Returns a Wallet instance with a zero balance.'''
    return Wallet()

@pytest.mark.parametrize("earned, spent, expected", [
    (30, 10, 20),
    (20, 2, 18),
])
def test_transactions(my_wallet, earned, spent, expected):
    my_wallet.add_cash(earned)
    my_wallet.spend_cash(spent)
    assert my_wallet.balance == expected

【讨论】:

【参考方案4】:

它通常被禁用(1、2)。

有一个pylint-pytest 插件试图修复一些问题,但错误W0621 尚未修复。

【讨论】:

这个插件是否在pytest期间对pylint警告出错,而不是在测试代码中抑制pylint警告? 是的,插件 @insysion 链接到运行 pylint 作为 pytest 的一部分,与修复常见 pytest 夹具使用的 pylint 错误消息无关。 此插件在使用“启用”pytest 配置时似乎无法正常工作。任何“启用”的标志都优先于 pylint-pytest 尝试做的事情。

以上是关于pytest 固定装置从外部范围重新定义名称 [pylint]的主要内容,如果未能解决你的问题,请参考以下文章

pytest 固定装置按啥顺序执行?

我可以将参数传递给 pytest 固定装置吗?

pytest 如何以及在哪里找到固定装置

4.pytest中固定装置setup和teardown

在外部范围中定义的阴影名称有啥问题?

python 交易装置pytest