ncopiy
ncopiy

Reputation: 1604

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)?

Upvotes: 5

Views: 3904

Answers (2)

hoefling
hoefling

Reputation: 66171

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

Upvotes: 10

ar-m-an
ar-m-an

Reputation: 1561

ApiTestCase is a subclass of unittest.TestCase which would not support parametrization as mentioned in pytest docs:

The following pytest features work in unittest.TestCase subclasses:

  • Marks: skip, skipif, xfail;
  • Auto-use fixtures;

The following pytest features do not work, and probably never will due to different design philosophies:

  • Fixtures (except for autouse fixtures, see below);
  • Parametrization;
  • Custom hooks;

Third party plugins may or may not work well, depending on the plugin and the test suite.

Upvotes: 7

Related Questions