Plain is headed towards 1.0! Subscribe for development updates →

Testing - pytest

Write and run tests with pytest.

Django includes its own test runner and unittest classes. But a lot of people (myself included) prefer pytest.

In Plain I've removed the Django test runner and a lot of the implications that come with it. There are a few utilities that remain to make testing easier, and plain-test is a wrapper around pytest.

 1import pytest
 2from plain.runtime import settings as plain_settings
 3from plain.runtime import setup
 4from plain.test.client import Client, RequestFactory
 5
 6
 7def pytest_configure(config):
 8    # Run Plain setup before anything else
 9    setup()
10
11
12@pytest.fixture(autouse=True, scope="session")
13def _allowed_hosts_testserver():
14    # Add testserver to ALLOWED_HOSTS so the test client can make requests
15    plain_settings.ALLOWED_HOSTS = [*plain_settings.ALLOWED_HOSTS, "testserver"]
16
17
18@pytest.fixture()
19def client() -> Client:
20    """A Plain test client instance."""
21    return Client()
22
23
24@pytest.fixture()
25def request_factory() -> RequestFactory:
26    """A Plain RequestFactory instance."""
27    return RequestFactory()
28
29
30@pytest.fixture()
31def settings():
32    class SettingsProxy:
33        def __init__(self):
34            self._original = {}
35
36        def __getattr__(self, name):
37            return getattr(plain_settings, name)
38
39        def __setattr__(self, name, value):
40            if name.startswith("_"):
41                super().__setattr__(name, value)
42            else:
43                if name not in self._original:
44                    self._original[name] = getattr(plain_settings, name, None)
45                setattr(plain_settings, name, value)
46
47        def _restore(self):
48            for key, value in self._original.items():
49                setattr(plain_settings, key, value)
50
51    proxy = SettingsProxy()
52    yield proxy
53    proxy._restore()