2017-10-16 109 views
1

我的自动化框架使用pytest设置/测试,而不是固定装置的拆卸式。我也有类的几个层次:pytest:安装/拆卸方法的过程中获取参数多态值

BaseClass - 最高的,所有测试inhriet从中

FeatureClass - 中,涉及到程序的所有测试功能,从它继承

TestClass - 保持实际测试

编辑,为例子起见,我改变DB调用一个简单的打印

我想在所有设置/拆卸中添加数据库报告。即我想,一般BaseClasssetup_method将创建测试DB项,teardown_method将改变的结果的条目。我已经试过,但我似乎无法在运行时脱身方法的当前运行的测试值。甚至可能吗?如果不是,我该怎么办呢?

样品: (在base.py)

class Base(object): 

    test_number = 0 
    def setup_method(self, method): 
     Base.test_number += 1 
     self.logger.info(color.Blue("STARTING TEST")) 
     self.logger.info(color.Blue("Current Test: {}".format(method.__name__))) 
     self.logger.info(color.Blue("Test Number: {}".format(self.test_number))) 
     # --->here i'd like to do something with the actual test parameters<--- 
     self.logger.info("print parameters here") 

    def teardown_method(self, method): 
     self.logger.info(color.Blue("Current Test: {}".format(method.__name__))) 
     self.logger.info(color.Blue("Test Number: {}".format(self.test_number))) 
     self.logger.info(color.Blue("END OF TEST")) 

(在my_feature.py)

class MyFeature(base.Base): 

    def setup_method(self, method): 
     # enable this feature in program 
     return True 

(在test_my_feature.py)

class TestClass(my_feature.MyFeature): 

    @pytest.mark.parametrize("fragment_length", [1,5,10])  
    def test_my_first_test(self): 
     # do stuff that is changed based on fragment_length 
     assert verify_stuff(fragment_length) 

所以我怎样才能获得setup_method的参数,基本父类的测试框架的?

+0

是否使用'unittest.TestCase'?然后,您可以将'setup'中的值设置为'self'并在测试中检索它。需要更多详细信息才能回答此问题。 – Arunmozhi

+0

@Arunmozhi我已经添加了一些基本的代码,希望它会澄清什么,我试图做 –

回答

2

简要的回答:不,你不能做到这一点。是的,你可以解决它。


的时间长一点:这些单元测试样式设置&拆解只为与单元测试风格测试兼容性完成。他们不支持pytest的夹具,这使pytest更好。

由于这个原因,既不pytest也不pytest的单元测试插件提供这些安装/拆卸方法的上下文。如果您有request,function或其他上下文对象,您可以通过request.getfuncargvalue('my_fixture_name')动态获取灯具的值。

但是,您拥有的全部是self/clsmethod作为测试方法对象本身(即不是pytest的节点)。

如果你看看_pytest/unittest.py插件里面,你会发现这个代码:

class TestCaseFunction(Function): 
    _excinfo = None 

    def setup(self): 
     self._testcase = self.parent.obj(self.name) 
     self._fix_unittest_skip_decorator() 
     self._obj = getattr(self._testcase, self.name) 
     if hasattr(self._testcase, 'setup_method'): 
      self._testcase.setup_method(self._obj) 
     if hasattr(self, "_request"): 
      self._request._fillfixtures() 

首先,请注意setup_method()被称为完全从pytest的对象(例如self作为测试节点)分离。

二,请注意setup_method()被称为后准备的灯具。所以即使你可以访问它们,它们也不会准备好。

所以,一般来说,你不能这样做,没有一些欺骗。


对于诡计,必须定义一次pytest钩/ hookwrapper,并记住pytest节点正在执行:

conftest.py或任何其他插件:

import pytest 

@pytest.hookimpl(hookwrapper=True) 
def pytest_runtest_protocol(item, nextitem): 
    item.cls._item = item 
    yield 

test_me.py

import pytest 


class Base(object): 
    def setup_method(self, method): 
     length = self._item.callspec.getparam('fragment_length') 
     print(length) 


class MyFeature(Base): 
    def setup_method(self, method): 
     super().setup_method(method) 


class TestClass(MyFeature): 
    @pytest.mark.parametrize("fragment_length", [1,5,10])  
    def test_my_first_test(self, fragment_length): 
     # do stuff that is changed based on fragment_length 
     assert True # verify_stuff(fragment_length) 

还要注意的是MyFeature.setup_method()亩st由于显而易见的原因,请致电父母的super(...).setup_method()

cls._item将在每个callspec(即,与每个参数的每个函数调用)来设置。如果您愿意,您也可以将项目或特定参数放入其他全局状态。

另外要小心不要保存在item.instance领域。该类的实例将在稍后创建,并且您必须使用setup_instance/teardown_instance方法。否则,保存的实例字段不会保留,并且不可用在setup_method()中。

下面是执行:

============ test session starts ============ 
...... 
collected 3 items                                         

test_me.py::TestClass::test_my_first_test[1] 1 
PASSED 
test_me.py::TestClass::test_my_first_test[5] 5 
PASSED 
test_me.py::TestClass::test_my_first_test[10] 10 
PASSED 

============ 3 passed in 0.04 seconds ============ 
+0

感谢详细的答复,这真的帮助我理解pytest更好。我会试着去实现这个。我看你明确地使用“fragment_length”得到它的价值,所以如果我想获得的所有参数的测试一定有我需要得到self._item.callspec.params和遍历它的价值观? –

+1

@AvishayCohen我不能肯定地说,但很可能是的。这里的所有字段和方法都是pytest的高级API的一部分。唯一的问题是item/node/callspec没有暴露给unittest的类/方法。我认为,这是为了向后兼容unittest而设计的,并不适用于正常的pytest使用。 –

+0

是的。它工作得很好! –