将 pytest 参数化与 DRF 测试一起使用

Using pytest parametrize with DRF test

现在我有这样的代码:

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

每次失败并出现以下错误:

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

如何在 DRF 测试 class 的 APITestCase 内部使用 @pytest.mark.parametrize 装饰器进行测试?
也许还有另一种方法来参数化测试(但不是循环)?

ApiTestCaseunittest.TestCase 的子类,不支持 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.

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

从 Python 3.4 开始,参数化在标准库中可用 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

但是,如果您想从使用 pytest 中获得真正的好处,请考虑从 unittest 式 class 测试转移到测试函数。使用 pytest 结合 pytest-django 插件的相同测试:

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

编辑

您还可以查看 parameterized 库,它为测试 class 方法提供了类似于 pytest 的参数化。示例:

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