使用[Django REST Framework]以及pytest-freezegun来人为地推进时间流逝的过程
简介
介绍 pytest-freezegun 的使用方法。
目标、目标、方向、意图、目标
可以了解 pytest-freezegun 的基本使用方法。
运用技术
python = 3.11.2
Django = 4.2.3
djangorestframework = 3.14.0
pytest = 7.3.1
factory-boy = 3.2.1
pytest-freezegun = 0.4.2
关于测试概要和API规范
本次将使用登出API。
一旦登录,应该会保持1小时的会话时间,但我们将测试确保会话是否真的在1小时后失效。
如果会话失效,使用登出API将会导致认证错误。
由于使用 client.login() 来进行登录(返回布尔值),因此判断中不使用 user.is_authenticated,而是使用登出 API。
我们马上来看一下。
首先,让我们安装库。
$ pip install pytest-freezegun
定义要使用的装置
import pytest
from datetime import datetime, timedelta
from django.core.management import call_command
from django.contrib.auth.models import Group
from rest_framework.test import APIClient
from app.models import Employee, User
from app.tests.factories.employee import EmployeeFactory
from app.tests.factories.user import UserFactory
@pytest.fixture(scope="session")
def django_db_setup(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
call_command("loaddata", "test.json")
@pytest.fixture
def admin_user():
"""admin権限ユーザーを作成"""
group = Group.objects.get(name="admin")
user = UserFactory(groups_id=group.id)
return EmployeeFactory(user=user)
@pytest.fixture
def client(db):
"""APIクライアントを作成"""
return APIClient()
@pytest.fixture
def login_user(client):
"""権限を指定してログインを実施"""
def _method(employee):
client.login(
id=employee.id,
password="password",
)
return _method
@pytest.fixture
def get_logout_url():
"""ログアウトAPIのURL"""
return "/api/logout/"
@pytest.fixture
def freeze_time(freezer):
"""指定した時間まで経過させる"""
def _method(hours, minutes, seconds):
mock_now = datetime.now() + timedelta(
hours=int(hours), minutes=int(minutes), seconds=int(seconds)
)
freezer.move_to(mock_now)
return _method
@pytest.fixture
def unauthorized_message():
"""認証情報が含まれていない場合のエラーメッセージ"""
return {"detail": "認証情報が含まれていません。"}
@pytest.fixture
def logout_message():
"""ログアウトが成功した場合のメッセージ"""
return {"detail": "ログアウトしました"}
这是实际的测试代码。
在经过59分59秒后,会继续保留会话,因此不会出现错误。
import pytest
from rest_framework import status
@pytest.mark.django_db
def test_admin_user_does_not_auto_logout_near_expiry(
client, login_user, admin_user, get_logout_url, freeze_time, logout_message
):
"""admin権限ユーザーがログインして59分59秒経過後、自動的にログアウトされないか"""
login_user(admin_user)
freeze_time(0, 59, 59)
response = client.post(get_logout_url, format="json")
assert response.status_code == status.HTTP_200_OK
assert response.json() == logout_message
然而,当经过1小时后执行注销API时,将出现身份验证错误(会话已过期)。
@pytest.mark.django_db
def test_admin_user_logout_session_expired(
client, login_user, admin_user, get_logout_url, freeze_time, unauthorized_message
):
"""admin権限ユーザーがログインして1時間経過後、自動的にログアウトされるか"""
login_user(admin_user)
freeze_time(1, 0, 0)
response = client.post(get_logout_url, format="json")
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert response.json() == unauthorized_message
关于使用freezegun的fixture
@pytest.fixture
def freeze_time(freezer):
"""指定した時間まで経過させる"""
def _method(hours, minutes, seconds):
mock_now = datetime.now() + timedelta(
hours=int(hours), minutes=int(minutes), seconds=int(seconds)
)
freezer.move_to(mock_now)
return _method
冰箱已经作为一个设备被默认准备好了,通过在 freeze_time 函数内部定义一个 _method 来使用该设备时可以传递参数。
这是一个使用的例子。
freeze_time(0, 59, 59)
# 0時間59分59秒
freeze_time(1, 0, 0)
# 1時間0分0秒
请以习得者的母语中文进行改写,仅需要一个版本:
请参考
- pytest-freezegun PYPI