How to write a unit test a custom Filter in Django rest framework?

Viewed 393

I am new to Django, so maybe this is very simple, but I have been trying to make sense of the documentation all day and I need some help, some way to going in the right direction. Basically, I have a Custom Filter class, like this

class CustomFilter(django_filters.rest_framework.FilterSet):
    username = BooleanFilter(method='filter_current_user')
    ...

And inside, several methods, being the following the simpler of them

def filter_current_user(self, queryset, name, value):
        if value is True:
            return queryset.filter(user=self.request.user)
        return queryset

How can I write a test that validates the differences of the queryset returned when value is True and when value is False? My biggest problem is how make that the self value contains the request.user.

1 Answers

The best way I found for testing a filter class is to validate the raw query that is produced with it:

class ConversationFilter(ConversationFilterSet):
    created = filters.ChoiceFilter(choices=CREATED_CHOICES, method="filter_created")

    def filter_created(self, queryset: QuerySet, name: str, value: str) -> QuerySet:
        if value:
            if value == "more_than_7_days":
                time_stop = timezone.now() - timedelta(days=7)
                return queryset.filter(created_time__lte=time_stop)
            elif value == "last_12_hours":
                value_serialized = timedelta(hours=12)
            elif value == "last_24_hours":
                value_serialized = timedelta(hours=24)
            elif value == "last_3_days":
                value_serialized = timedelta(days=3)
            elif value == "last_7_days":
                value_serialized = timedelta(days=7)
            else:
                raise ValueError(value)
            time_start = timezone.now() - value_serialized
            queryset = queryset.filter(created_time__gte=time_start)

        return queryset


@pytest.mark.usefixtures("db")
class TestConversationFilter:
    def test_filter_created_more_than(self):
        queryset = Conversation.objects.all()
        view = ConversationsInboxViewSet.as_view({"get": "list"})
        conversation_filter = ConversationFilter(view=view)
        filtered_queryset = conversation_filter.filter_created(
            queryset, "created", "more_than_7_days"
        )

        # We're checking only the datetime up to the level of seconds - below that we'd need to add
        # The time required to evaluate the expression etc.
        created_time_parameter: str = (timezone.now() - timedelta(days=7)).strftime(
            "%Y-%m-%d %H:%M:%S"
        )

        assert (
            f'WHERE "conversations_conversation"."created_time" <= {created_time_parameter}'
            in str(filtered_queryset.query)
        )
Related