【问题标题】:Pytest - Fixture introspect on function levelPytest - 功能级别的夹具自省
【发布时间】:2015-11-05 15:42:26
【问题描述】:

我有一个需要来自测试函数的变量的夹具。如果函数级别的自省有效,则使用自省并在函数命名空间/上下文中声明变量应该可以工作,就像它在模块级别一样,但是每次我运行代码时,我都会以 None 而不是字符串“Fancy Table”结束。

在夹具中,我将范围设置为“函数”,然后通过 getattr 和 request.function 进行内省:

#conftest.py
@pytest.fixture(scope='function')
def table(request):
    from data_setup import create_table
    table_name = getattr(request.function, "table_name", None)
    create_table(request, table_name)

我在测试函数中声明了变量table_name:

#test_file.py
class TestTable():

    @pytest.mark.tags("table")
    def test_create_table(self, test_db):
        table_name = "Fancy Table"
        current_page = TablePage(self.test_driver, test_db)
        current_page.go_to_kitchen("Eva", "Evas Kitchen")
        current_page.create_first_table(expected_table_name)
        Validation.assert_equal(expected_table_name, current_page.get_name(), "Table had the wrong name!")

在模块级别上这样做是有效的,就像类一样,但是一旦我尝试在功能级别上这样做,夹具就会再次吐出 None 。我在功能级别上使用夹具自省错误吗?不这样怎么用?

【问题讨论】:

    标签: python pytest fixtures introspection


    【解决方案1】:

    函数变量是局部的,在函数返回后被销毁,它们不以任何方式绑定函数对象……这就是 Python 的工作方式,与 py.test 无关。

    如果您将 table_name 局部变量显式绑定到测试函数,您的示例将有效,有效地让它比通常的生命周期更长:

    @pytest.mark.tags("table")
    def test_create_table(self, test_db):
        test_create_table.table_name = "Fancy Table"
    

    另一方面,将table_name 显式传递给TablePage 不是更简单吗?它会更简单,直接,而且,明确。 :)

    【讨论】:

      【解决方案2】:

      将局部变量显式绑定到测试函数导致我的 IDE 抱怨 Unresolved 引用。我们还需要知道什么才能完成这项工作?

      在给出的示例中,当我编写 test_create_table.table_name = "Fancy Table" 时,test_create_table 部分是我的 IDE 抱怨的部分,其中包含未解析的引用。因此,鉴于我收到未解决的引用错误,我怎样才能成功地显式绑定局部变量?

      【讨论】:

        【解决方案3】:

        出于某种原因,布鲁诺提供的解决方案对我不起作用。这就是我所做的

        import inspect
        
        @pytest.fixture(scope='function')
        def custom_fixture(request):
            sig = inspect.signature(request.function)
        
            my_fixture_obj = None
        
            if 'fixture_data' in sig.parameters:
                fixture_data = sig.parameters['fixture_data'].default
        
                my_fixture_obj = MyFixtureObject(fixture_data['data'])
        
            yield my_fixture_obj
        
            # cleanup my_fixture_obj
        
        
        def test_sample1(custom_fixture, fixture_data = {'data': ['s1', 's2', 's3']}):
            ...
        
        def test_sample2(custom_fixture, fixture_data = {'data': ['a1', 'a2', 'a3']}):
            ...
        

        【讨论】:

          猜你喜欢
          • 2020-12-06
          • 2014-08-21
          • 1970-01-01
          • 2018-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-14
          • 2023-03-11
          相关资源
          最近更新 更多