简体   繁体   English

Django / Python unittest side_effect用法

[英]Django / Python unittest side_effect usage

The second in what might become a series in "unittesting strange code". 这可能成为“单元测试奇怪代码”系列中的第二篇。 I have the following function I am testing: 我正在测试以下功能:

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

First off let me assure you I realise that this is... ugly. 首先,让我向您保证,我意识到这很丑。 It's a sad requirement for now that we are using two different django tag libraries, django-taggit and django-taggable. 现在,我们要使用两个不同的django标记库django-taggit和django-taggable,这是一个可悲的要求。 (Never use django-taggable). (切勿使用django-taggable)。 And this is about as generic a way as I can think of to have a filter function that works with both with the minimum amount of fuss. 正如我所想到的,这是一种通用的方法,它具有在最小的麻烦情况下可以同时使用两者的过滤器功能。 The issue that occurs when testing is that in order to test the functionality, I need to get queryset.filter() to raise a FieldError(). 测试时发生的问题是,为了测试功能,我需要获取queryset.filter()来引发FieldError()。 Fine, easily done with setting it up as a mock object with a side effect: 很好,很容易将其设置为具有副作用的模拟对象:

  def side_effect(*args, **kwargs):
        if kwargs.get("tags__name__in", None):
            return FieldError()

    mock_queryset = MagicMock()
    mock_queryset.filter.side_effect = side_effect

The issue with this is that because of the FieldError being raised, filter() can no longer be used in the except part of the function, meaning I cannot test for the correct called_count, or assert_any_call() etc. 这样做的问题是,由于引发了FieldError,因此无法在该函数的except部分使用filter(),这意味着我无法测试正确的named_count或assert_any_call()等。

Other than an upheaval of the codebase to only use one version of tagging, what are the ways around this? 除了仅使用一种版本的标记的代码库发生剧变外,该如何解决?

Just make a separate function that raises FieldError if it's called one way, and doesn't in the other: 只需创建一个单独的函数,以一种方式引发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

et cetera. 等等。 I see now that you already do that with your side effect function, you can just do the same but more. 我现在看到,您已经可以使用副作用功能执行此操作,您可以执行相同操作但执行更多操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM