Search code examples
djangodjango-rest-frameworkpytestdjango-testingpytest-django

Using pytest parametrize with DRF test


Now I have code like this:

from rest_framework.test import APITestCase

class MyTestClass(ApiTestCase):
    fixtures = ['some_fixtures.json', ]

    @pytest.mark.parametrize('field, reverse_ordering', [
        ('id', False),
        ('id', True)])
    def test_ordering(self, field, reverse_ordering):
        # some test function

Every time it is failed with that error:

======================================================================
ERROR: test_ordering (my_module.tests.MyTestClass)
----------------------------------------------------------------------
TypeError: test_ordering() missing 2 required positional arguments: 'field' and 'reverse_ordering'

How it is possible to use @pytest.mark.parametrize decorator with tests inside of APITestCase from DRF tests class?
Maybe there is some another way to parametrize tests (but not loops)?


Solution

  • Maybe there is some another way to parametrize tests (but not loops)?

    Since Python 3.4, parametrizing is available in the standard library using subTest:

    class MyTest(APITestCase):
    
        test_ordering_params = [('id', False), ('id', True)]
    
        def test_ordering(self):
            for field, reverse_ordering in self.test_ordering_params:
                with self.subTest(field=field, reverse=reverse_ordering):
                    query = ('-' if reverse_ordering else '') + field
                    resp = self.client.get(reverse('url-name'), {'ordering': query}, format='json')
                    assert resp.data
    

    However, if you want to gain real benefits from using pytest, consider moving away from unittest-style class tests to test functions. The same test using pytest combined with pytest-django plugin:

    import pytest
    from rest_framework.test import APIClient
    
    @pytest.fixture
    def apiclient():
        return APIClient()
    
    @pytest.mark.parametrize('field, reverse_ordering', [('id', False), ('id', True)])
    def test_ordering(apiclient, db, field, reverse_ordering):
        query = ('-' if reverse_ordering else '') + field
        resp = apiclient.get(reverse('url-name'), {'ordering': query}, format='json')
        assert resp.data
    

    Edit

    You may also take a look at the parameterized library, which offers pytest-like parametrization for test class methods. Example:

    from parameterized import parameterized
    
    
    class MyTest(APITestCase):
    
        @parameterized.expand([('id', False), ('id', True)])
        def test_ordering(self, field, reverse_ordering):
            query = ('-' if reverse_ordering else '') + field
            resp = self.client.get(reverse('url-name'), {'ordering': query}, format='json')
            assert resp.data