我使用pytest.mark给我的测试kwargs。但是,如果我在类和类中的测试中使用相同的标记,则当两个使用相同的kwargs时,类的标记将覆盖函数上的标记。
import pytest
animal = pytest.mark.animal
@animal(species='croc') # Mark the class with a kwarg
class TestClass(object):
@animal(species='hippo') # Mark the function with new kwarg
def test_function(self):
pass
@pytest.fixture(autouse=True) # Use a fixture to inspect my function
def animal_inspector(request):
print request.function.animal.kwargs # Show how the function object got marked
# prints {'species': 'croc'} but the function was marked with 'hippo'
我的河马在哪里,我怎么能让他回来?
答案 0 :(得分:0)
不幸的是有pytest bugs related to this,我猜你正在碰到其中一个。{}我找到的那些与你不在那里做的子类有关。
答案 1 :(得分:0)
所以我一直在挖掘pytest代码并弄清楚为什么会这样。函数上的标记在导入时应用于函数,但类和模块级别标记不会在函数级别应用,直到测试集合为止。函数标记首先发生,并将它们的kwargs添加到函数中。然后类标记覆盖任何相同的kwargs,模块标记进一步覆盖任何匹配的kwargs。
我的解决方案是简单地创建我自己的修改过的MarkDecorator,它会在将kwargs添加到标记之前对其进行过滤。基本上,无论什么样的kwarg值首先被设置(似乎总是由函数装饰器设置)将始终是标记上的值。理想情况下,我认为应该在MarkInfo类中添加此功能,但由于我的代码没有创建实例,因此我使用 创建实例:MarkDecorator。请注意,我只更改源代码中的两行(关于keys_to_add的位)。
from _pytest.mark import istestfunc, MarkInfo
import inspect
class TestMarker(object): # Modified MarkDecorator class
def __init__(self, name, args=None, kwargs=None):
self.name = name
self.args = args or ()
self.kwargs = kwargs or {}
@property
def markname(self):
return self.name # for backward-compat (2.4.1 had this attr)
def __repr__(self):
d = self.__dict__.copy()
name = d.pop('name')
return "<MarkDecorator %r %r>" % (name, d)
def __call__(self, *args, **kwargs):
""" if passed a single callable argument: decorate it with mark info.
otherwise add *args/**kwargs in-place to mark information. """
if args and not kwargs:
func = args[0]
is_class = inspect.isclass(func)
if len(args) == 1 and (istestfunc(func) or is_class):
if is_class:
if hasattr(func, 'pytestmark'):
mark_list = func.pytestmark
if not isinstance(mark_list, list):
mark_list = [mark_list]
mark_list = mark_list + [self]
func.pytestmark = mark_list
else:
func.pytestmark = [self]
else:
holder = getattr(func, self.name, None)
if holder is None:
holder = MarkInfo(
self.name, self.args, self.kwargs
)
setattr(func, self.name, holder)
else:
# Don't set kwargs that already exist on the mark
keys_to_add = {key: value for key, value in self.kwargs.items() if key not in holder.kwargs}
holder.add(self.args, keys_to_add)
return func
kw = self.kwargs.copy()
kw.update(kwargs)
args = self.args + args
return self.__class__(self.name, args=args, kwargs=kw)
# Create my Mark instance. Note my modified mark class must be imported to be used
animal = TestMarker(name='animal')
# Apply it to class and function
@animal(species='croc') # Mark the class with a kwarg
class TestClass(object):
@animal(species='hippo') # Mark the function with new kwarg
def test_function(self):
pass
# Now prints {'species': 'hippo'} Yay!