可能成为“单元测试奇怪代码”系列的第二部分。我正在测试以下功能:
def filter_queryset(self):
"""
Filter our base queryset
"""
# Get our base queryset
queryset = self.get_queryset()
if self.tags:
try:
# Try the django-taggit way of filtering by tags
queryset = queryset.filter(tags__name__in=self.tags)
except FieldError:
# Our queryset object is using django-taggable instead
# filter by tags the ugly way...
for tag in self.tags:
queryset = queryset.filter(tags__icontains=tag)
return queryset
首先让我向你保证,我意识到这......丑陋。现在我们正在使用两个不同的django标签库,django-taggit和django-taggable,这是一个悲哀的要求。 (切勿使用django-taggable)。这是一种通用的方式,我可以想到有一个过滤器功能,可以与最小量的大惊小怪。测试时发生的问题是,为了测试功能,我需要获取queryset.filter()来引发FieldError()。很好,很容易将其设置为具有副作用的模拟对象:
def side_effect(*args, **kwargs):
if kwargs.get("tags__name__in", None):
return FieldError()
mock_queryset = MagicMock()
mock_queryset.filter.side_effect = side_effect
这个问题是因为引发了FieldError,所以filter()不能再用在函数的except
部分,这意味着我无法测试正确的called_count或assert_any_call()等
除了代码库的动荡只使用一个版本的标记之外,有什么方法呢?
答案 0 :(得分:1)
只需创建一个单独的函数,如果它被单向调用,则会引发FieldError,而在另一个函数中则不会:
expected_return = MagicMock()
def fake_filter(**kwargs):
if 'tags__name__in' in kwargs:
raise FieldError()
if 'tags__icontains' in kwargs:
return expected_return
raise ValueError("Neither expected kwarg present")
mock_queryset = MagicMock()
mock_queryset.filter = fake_filter
等等。我现在看到你已经用你的副作用功能做到了,你可以做同样的事情但更多。