Using pytest parametrize with DRF test
Asked Answered
T

2

5

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

Third answered 14/9, 2018 at 12:47 Comment(0)
R
10

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
Rebroadcast answered 14/9, 2018 at 20:54 Comment(5)
I am using subTest now, but i do not like the way it looks. All my test classes are inherited from my own specific BaseTestClass(ApiTestCase). (I mean I can not rewrite it for separated test functions)Third
From my experience, any functionality residing in a base test class can be always refactored to a fixture, resulting in less boilerplate code in the end. But of course, if you already have hundreds of unittest-style tests, refactoring all of them is a monstruous task to be done at once.Rebroadcast
You may also take a look at the parameterized library, which offers pytest-like parametrization for test class methods. I have updated the answer with a usage example.Rebroadcast
Thank you, i'll use it!Third
Glad I could help!Rebroadcast
K
7

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.

Kinescope answered 14/9, 2018 at 13:9 Comment(1)
I've updated question here (last line). It is ok, I can not use it. But what I can use like parametrize?Third

© 2022 - 2024 — McMap. All rights reserved.