【求助】pytest hook函数pytest_generate_tests的问题,希望老师解答一下

问题:课程上讲的pytest_generate_tests的用法中,为什么把参数放到class类里面,就会报错呢?

# 测试代码:
import yaml

# param1 要与conftest.py 里面处理的param1 保持一致
class TestParam:
    with open('datas/a.yml') as f:
        datas = yaml.safe_load(f)
        # myids 和mydatas 要与conftest.py 勾子函数里面的
        # metafunc.module.datas, ids=metafunc.module.myids 保持一致
        myids = datas.keys()
        mydatas = datas.values()

    def test_param(self, param1):
        print(f"param = {param1}")
        print("动态生成测试用例")

#  conftest.py
def pytest_generate_tests(metafunc: "Metafunc") -> None:
    if "param1" in metafunc.fixturenames:
        metafunc.parametrize("param1",
                             metafunc.module.mydatas,
                             ids=metafunc.module.myids,
                             scope='function')

# 执行结果:
test_param.py:None (test_param.py)
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/hooks.py:286: in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/manager.py:93: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/manager.py:87: in <lambda>
    firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/_pytest/python.py:246: in pytest_pycollect_makeitem
    res = list(collector._genfunctions(name, obj))
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/_pytest/python.py:454: in _genfunctions
    self.ihook.pytest_generate_tests.call_extra(methods, dict(metafunc=metafunc))
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/hooks.py:324: in call_extra
    return self(**kwargs)
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/hooks.py:286: in __call__
    return self._hookexec(self, self.get_hookimpls(), kwargs)
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/manager.py:93: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
../../../new_test_data/mno_test/venv/lib/python3.7/site-packages/pluggy/manager.py:87: in <lambda>
    firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
conftest.py:74: in pytest_generate_tests
    metafunc.module.mydatas,
E   AttributeError: module 'test_param' has no attribute 'mydatas'

感谢!!

我猜是因为你把生成myids和mydatas这两个步骤放在了with下面,当上下文结束时还没有对它做引用,那么这部分内存就被回收了。试试修改下

with open('datas/a.yml') as f:
        datas = yaml.safe_load(f)
        # myids 和mydatas 要与conftest.py 勾子函数里面的
        # metafunc.module.datas, ids=metafunc.module.myids 保持一致
myids = datas.keys()
mydatas = datas.values()

谢谢你的回复。
但是我试了一下,还是同样的报错。

你看它的报错,是test_param对象中没有,mydates,那就代表你在回调param1时的module里面是没有mydatas和myids的,那么你这两句必然报错,你这个module是个啥。

module是进行参数化的测试用例所在的模块对象。
问题就是为啥test_param 里面为啥没有mydatas参数的。。。
如果不把

with open('datas/a.yml') as f:
        datas = yaml.safe_load(f)
        # myids 和mydatas 要与conftest.py 勾子函数里面的
        # metafunc.module.datas, ids=metafunc.module.myids 保持一致
        myids = datas.keys()
        mydatas = datas.values()

这段代码放到类外面,就能够成功。

这个问题为什么没有人回答呢,是我没有描述清楚吗 :sob:
@xixi-tech 请求老师给解答一下吧,就是pytest课程中讲过的

因为你把参数获取放在了类中,所以参数是一个类变量
但是你的获取方式是从module去获取,也就是通过模块去获取,这样并不能获取到类下面的类变量
可以换成 metafunc.cls.mydatasmetafunc.cls.myids试一下 从类中获取

1 个赞

解决了,谢谢老师! :rose: