【django】pytest fixtureの使い方

当ページのリンクには広告が含まれています。
  • URLをコピーしました!

サンプルコードはこちら

Django/DjangoRESTframeworkについて記事まとめ

目次

fixture | テストで使用するリソースの定義

fixtureは、djangoのモデルにアクセスしたり、モックを作成したり出来る機能です。

https://docs.pytest.org/en/6.2.x/fixture.html

@pytest.fixtureとして関数を作成することで、その返り値を利用できるようになります。

import pytest

@pytest.fixture
def fixture_1():
    print('run-fixture-1')
    return 1

def test_example1(fixture_1):
    num = fixture_1
    assert num == 1

fixtureの値を使い回す範囲設定(scope)

fixtureは、標準では使用するテスト関数毎に呼び出され利用できます。

@pytest.fixture
def fixture_1():
    print('run-fixture-1')
    return 1

def test_example1(fixture_1):
    print("example1")
    num = fixture_1
    assert num == 1

def test_example2(fixture_1):
    print("example2")
    num = fixture_1
    assert num == 1

pytest -rPを実行すると

===================================== PASSES ===================================== 
_________________________________ test_example1 __________________________________ 
----------------------------- Captured stdout setup ------------------------------ 
run-fixture-1
------------------------------ Captured stdout call ------------------------------ 
example1
_________________________________ test_example2 __________________________________ 
----------------------------- Captured stdout setup ------------------------------ 
run-fixture-1
------------------------------ Captured stdout call ------------------------------ 
example2
=============================== 2 passed in 0.05s ================================ 

毎回呼び出されていることが確認できました。しかし、実行にコストがかかり値を共有したい場合には、scope=""と指定できます。

例えば、@pytest.fixture(scope="session")とすることで、再利用される形に変更できます。

===================================== PASSES ===================================== 
_________________________________ test_example1 __________________________________ 
----------------------------- Captured stdout setup ------------------------------ 
run-fixture-1
------------------------------ Captured stdout call ------------------------------ 
example1
_________________________________ test_example2 __________________________________ 
------------------------------ Captured stdout call ------------------------------ 
example2
=============================== 2 passed in 0.05s ================================

他にもscopeの種類としては

  • function(デフォルト値)
  • class
  • module
  • package
  • session

があります。

django_db | データベースアクセスを明示

https://pytest-django.readthedocs.io/en/latest/helpers.html

データベースへのアクセスが必要なテストの場合、@pytest.mark.django_dbを使用します。

テスト関数の引数にdbと記述してもデータベースへのアクセスは可能です。

下記では、django標準のユーザーモデルを作成し、ユーザー数のチェックを行いました。

import pytest

from django.contrib.auth.models import User

@pytest.mark.django_db
def test_user_create():
    User.objects.create_user('test', 'test@test.com', 'test')
    assert User.objects.count() == 1

@pytest.mark.django_db
def test_user_create1():
    count = User.objects.all().count
    assert count == 0

テスト用に用いられるデータベースは、テスト用データベースとして独立しており、テスト完了後に破棄されます。また、関数毎に独立しておりどこかの関数で使用したデータは保持されません。

fixtureからUserモデルを作成し、テストで使用することも可能です。

import pytest

from django.contrib.auth.models import User

@pytest.fixture
def user_1(db):
    user = User.objects.create_user('test-user')
    print('create-user')
    return user

@pytest.mark.django_db
def test_set_check_password(user_1):
    user_1.set_password('new-password')
    assert user_1.check_password("new-password") is True

@pytest.mark.django_db
def test_set_check_password1(user_1):
    assert user_1.username == 'test-user'

create_userで新しいユーザーを作成しました。

テストでは

  • set_passwordcheck_passwordでパスワードの検証
  • usernameが正しいかどうかの検証

を行いました。

fixtureを共有する(conftest.py)

conftest.pyで作成したfixtureは、ファイル間で共有できます。

conftest.pyの有効範囲はディレクトリ単位になります。

Factory & fixture

fixtureの結果が、1回のテストで複数回必要となる状況の場合には、動的にデータを生成する関数(Factory)を定義すると便利です。

データを直接返す代わりにデータを生成する関数を作成します。

import pytest

from django.contrib.auth.models import User

@pytest.fixture
def new_user_factory(db):
    def create_app_user(
        username: str,
        password: str = None,
        first_name: str = "firstname",
        last_name: str = "lastname",
        email: str = "test@test.com",
        is_staff: str = False,
        is_superuser: str = False,
        is_active: str = True
    ):
        user = User.objects.create_user(
            username=username,
            password=password,
            first_name=first_name,
            last_name=last_name,
            email=email,
            is_staff=is_staff,
            is_superuser=is_superuser,
            is_active=is_active,
        )
        return user
    return create_app_user

@pytest.fixture
def new_user1(db, new_user_factory):
    return new_user_factory("Test_user","password","MyName")

@pytest.fixture
def new_user2(db, new_user_factory):
    return new_user_factory("Test_user","password", "MyName", is_staff="True")

new_user_factory(db)で新しくユーザーを作成するファクトリーを作成しました。

また、new_user1(db, new_user_factory)と他のfixtureとの連携も可能です。

import pytest

def test_new_user(new_user2):
    print(new_user2.is_staff)
    assert new_user2.is_staff

参考

サンプルコードはこちら

Django/DjangoRESTframeworkについて記事まとめ

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次