Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pytest.mark.parametrize with django.test.SimpleTestCase

Tags:

django

pytest

I am using pytest 3.2.2 and Django 1.11.5 on Python 3.6.2 on Windows.

The following code

import django.test
import pytest

class ParametrizeTest:
    @pytest.mark.parametrize("param", ["a", "b"])
    def test_pytest(self, param):
        print(param)
        assert False

works as expected:

scratch_test.py::ParametrizeTest::test_pytest[a] FAILED scratch_test.py::ParametrizeTest::test_pytest[b] FAILED

But as soon as I change it to use Django's SimpleTestCase, like this:

class ParametrizeTest(django.test.SimpleTestCase):
   ...

it fails with

TypeError: test_pytest() missing 1 required positional argument: 'param'

Can anybody explain why? And what to do against it?
(I actually even need to use django.test.TestCase and access the database.)

I have the following pytest plugins installed:

plugins: random-0.2, mock-1.6.2, django-3.1.2, cov-2.5.1

but turning any one of them (or all of them) off via -p no:random etc. does not help.

like image 271
Lutz Prechelt Avatar asked Jan 10 '18 16:01

Lutz Prechelt


People also ask

Can you use pytest with Django?

Setting Up pytest for a Django ProjectThe pytest-django plugin is maintained by the pytest development team. It provides useful tools for writing tests for Django projects using pytest .

What is pytest Mark Django_db?

pytest.mark. django_db([transaction=False, reset_sequences=False, databases=None]) This is used to mark a test function as requiring the database. It will ensure the database is set up correctly for the test. Each test will run in its own transaction which will be rolled back at the end of the test.

How does pytest parametrize work?

parametrize : parametrizing test functions. Parameter values are passed as-is to tests (no copy whatsoever). For example, if you pass a list or a dict as a parameter value, and the test case code mutates it, the mutations will be reflected in subsequent test case calls.


2 Answers

The Django test class is a unittest.TestCase subclass. Parametrization is unsupported and this is documented under the section pytest features in unittest.TestCase subclasses:


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

  • Fixtures (except for autouse fixtures)
  • Parametrization
  • Custom hooks

If you need parametrized tests and pytest runner, your best bet is to abandon the unittest style - this means move the setup/teardown into fixtures (pytest-django plugin has already implemented the hard parts for you), and use module level functions for your tests.

like image 130
wim Avatar answered Oct 05 '22 01:10

wim


Use @pytest.mark.django_db

Thanks, wim, for that helpful answer. RTFM, once again.

For clarity, here is the formulation that will work (equivalent to a test inheriting from TestCase, not just SimpleTestCase). Make sure you have pytest-django installed and then do:

import pytest

@pytest.mark.django_db
class ParametrizeTest:
    @pytest.mark.parametrize("param", ["a", "b"])
    def test_pytest(self, param):
        print(param)
        assert False

(BTW: Funnily, one reason why I originally decided to use pytest was that the idea of using plain test functions instead of test methods appealed to me; I like lightweight approaches.
But now I almost exclusively use test classes and methods anyway, because I prefer the explicit grouping of tests they provide.)

like image 32
Lutz Prechelt Avatar answered Oct 05 '22 01:10

Lutz Prechelt