Djangoでpytestを使う方法

DjangoでUTを書く時にはPythonunittestのサブクラスにしたdjango.test.TestCaseを用いることが出来る。

その一方で、他のUTを書くことも含めて考えると、pytestを利用したいケースも多く存在すると思われる。 Djangoでpytestを利用するにはpytest-djangoというライブラリをインストールする必要がある。

pytest-djangoのセットアップ方法

pytest-djangoのdocsに書いてある手順で構築すれば良い。

  1. pytest-djangoをpipでinstallする
  2. 設定ファイルにDJANGO_SETTINGS_MODULEを記述する

となる。特に2番目の定数値記述が必要であり、記述しない場合、pytestでtestできない状況に陥ってしまう。 どのようなケースになるかは後述する。

ドキュメント上では以下の3ファイルでの例が掲載されている。

  1. pytest.ini
  2. tox.ini
  3. pyproject.toml

失敗の備忘録

pytest.iniの時の失敗した記録。 ※tox, pyprojectでも同様のような結果になると予想している。

DJANGO_SETTINGS_MODULEを設定していない場合、具体的なファイルを指定した上でpytestを実行するとImproperlyConfigured が発生する。

root@f6ebfa8e11c6:/djangoTaskApp/mysite# pytest tasks/tests.py 
=============================================================== test session starts ===============================================================
platform linux -- Python 3.12.2, pytest-8.0.1, pluggy-1.4.0
rootdir: /djangoTaskApp
configfile: pytest.ini
plugins: cov-4.1.0, django-4.8.0, Faker-24.7.1
collected 0 items / 1 error                                                                                                                       

===================================================================== ERRORS ======================================================================
_____________________________________________________ ERROR collecting mysite/tasks/tests.py ______________________________________________________
tasks/tests.py:4: in <module>
    from django.contrib.auth.models import User
/usr/local/lib/python3.12/site-packages/django/contrib/auth/models.py:3: in <module>
    from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
/usr/local/lib/python3.12/site-packages/django/contrib/auth/base_user.py:57: in <module>
    class AbstractBaseUser(models.Model):
/usr/local/lib/python3.12/site-packages/django/db/models/base.py:129: in __new__
    app_config = apps.get_containing_app_config(module)
/usr/local/lib/python3.12/site-packages/django/apps/registry.py:260: in get_containing_app_config
    self.check_apps_ready()
/usr/local/lib/python3.12/site-packages/django/apps/registry.py:137: in check_apps_ready
    settings.INSTALLED_APPS
/usr/local/lib/python3.12/site-packages/django/conf/__init__.py:102: in __getattr__
    self._setup(name)
/usr/local/lib/python3.12/site-packages/django/conf/__init__.py:82: in _setup
    raise ImproperlyConfigured(
E   django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
============================================================= short test summary info =============================================================
ERROR tasks/tests.py - django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the env...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================================ 1 error in 0.18s =================================================================
root@f6ebfa8e11c6:/djangoTaskApp/mysite# 

こうしたケースを防ぐため、以下のように記述する必要がある。

[pytest]
DJANGO_SETTINGS_MODULE = mysite.settings

他の凡ミス

設定値にクォーテーションは不要だが、Pythonの文字列の癖でつい、(ダブル)クォーテーションを付与するミスをしたケース。

なお、これはpytest.iniまたはtox.iniで起こりうると予想している。 ドキュメントの例を見ると、pyproject.tomlではダブルクォーテーションで囲まれているため。

[pytest]
DJANGO_SETTINGS_MODULE = "mysite.settings"

この時はImportErrorが発生し、Python pathを追加するように言われてしまう。 が、実際にはクォーテーションが不要だったというオチだった。

ImportError: No module named '"mysite'

pytest-django found a Django project in . (it contains manage.py) and added it to the Python path.
If this is wrong, add "django_find_project = false" to pytest.ini and explicitly manage your Python path.