Reputation: 3384
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. (Never use 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(). 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.
Other than an upheaval of the codebase to only use one version of tagging, what are the ways around this?
Upvotes: 0
Views: 518
Reputation: 31260
Just make a separate function that raises FieldError if it's called one way, and doesn't in the other:
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.
Upvotes: 1