使用[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
广告
将在 10 秒后关闭
bannerAds