Django, DRF, JWT 및 OpenApi를 사용하여 적절한 RESTAPI 테스트 생성
이 글의 요점.
master
분기단계 #1 - pytest 설치 및 구성
본문에서 나는 당신이 pytest에 대해 잘 알고 있다고 가정합니다.없으면 먼저 읽으십시오this article
RESTAPI를 위한 테스트 작성부터 시작하겠습니다.우선, 우리는 pytest django (pytest의 포장기를 설치해야 한다. 이것은 우리가 더욱 복잡한 테스트를 쉽게 작성하는 데 도움을 줄 것이다) 를 설치하고 다음 명령을 사용하여 설치해야 한다.
pip install pytest-django
그리고pytest를 만들어야 합니다.ini 파일, pytest
우리 응용 프로그램에서 테스트를 실행하는 설정으로 사용됩니다.[pytest]
DJANGO_SETTINGS_MODULE = restapi_article.settings
python_files = tests.py test_*.py *_tests.py
2단계 - 프로필과 사용자 수를 검사하는 테스트를 작성합니다.
이제 우리는 테스트를 작성하기 시작할 수 있다.이전 글에서 우리는 신호를 사용하여 사용자와 함께 프로필을 만들었기 때문에, DB의 사용자 수와 프로필 수가 같은지 확인하기 위해 테스트를 작성합니다. (새 사용자를 만들고 프로필 수가 같은지 확인하기 바랍니다.)
@pytest.mark.django_db
decorator는 테스트에서 깨끗한 DB를 사용할 수 있도록 합니다. (현재는 기본 SQLite를 사용합니다.)그래서 실행pytest
은 우리의 settings.py
를 사용하여 설정을 사용할 것이다테스트 후, 모든 것이 테스트를 실행하기 전의 상태로 회복됩니다.첫 번째 간단한 테스트는 이렇습니다.
import pytest
from django.contrib.auth.models import User
from .models import Profile
@pytest.mark.django_db
def test_user_create_creates_profile():
User.objects.create_user('michal', '[email protected]', 'michalpassword')
assert Profile.objects.count() == 1
assert User.objects.count() == 1
3단계 - 사용자가 프로필을 편집할 수 있는지 확인하기 위한 테스트 작성
현재, 우리는 사용자가 개인 자료를 업데이트할 수 있는지 테스트해야 한다.따라서 테스트를 작성합시다. (앞의 테스트를 테스트 개요 파일로 확장할 것입니다.)수정된 테스트 용례는 다음과 같습니다.
ApiClient
에서 사용할 집게 rest_framework.test
를 추가해야 한다.추가 정보 tests.py
@pytest.fixture
def api_client():
from rest_framework.test import APIClient
return APIClient()
현재 우리는 이 클러치를 사용하여 이전의 테스트를 확장할 수 있다.테스트 이름을 변경했지만 사용자 수를 확인합니다.@pytest.mark.django_db
def test_user_can_update_his_profile(api_client):
user = User.objects.create_user('michal', '[email protected]', "michalpassword")
assert Profile.objects.count() == 1
assert User.objects.count() == 1
profile_url = reverse('profile-detail', args=[user.id])
user_url = reverse('user-detail', args=[user.id])
# check that profile was created for created user
response = api_client.get(profile_url)
assert response.status_code == 200
assert response.data['user'].endswith(user_url)
#create bio
bio_data = {
"user": response.data['user'],
"bio": "This is test user",
"location": "Wroclaw"
}
#create login data as user.password contains now encrypted string
login_data = {
"username": user.username,
"password": "michalpassword"
}
# get token
token_url = reverse('token_obtain_pair')
token = api_client.post(token_url, login_data, format='json')
# check that access token was sent in response
assert token.data['access'] is not None
# add http authorization header with Bearer prefix
api_client.credentials(HTTP_AUTHORIZATION='Bearer ' + token.data['access'])
# update profile
response = api_client.put(profile_url, bio_data, format='json')
# validate response
assert response.status_code == 200
assert response.data['bio'] == bio_data['bio']
assert response.data['location'] == bio_data['location']
이제 터미널 프로젝트 루트에 pytest
를 입력하여 테스트를 실행할 수 있습니다.우리의 테스트는 반드시 통과해야 한다. 어떠한 잘못도 없다.4단계 - 사용자가 자신의 프로필 이외의 다른 프로필을 편집할 수 없는지 확인하는 테스트를 작성합니다.
지금까지 우리의 응용 프로그램은 아무런 문제가 없었다.단, 다음 테스트에서 사용자 이외의 다른 프로필을 채워 보겠습니다.잘못된 JWT 영패로 다른 개요 파일을 업데이트할 때 오류 403을 볼 수 있습니다.다른 사람의 개인 정보를 변경할 수는 없지만...
@pytest.mark.django_db
def test_user_should_not_be_able_to_update_other_profile(api_client):
first_user = User.objects.create_user('michal', '[email protected]', "michalpassword")
second_user = User.objects.create_user('michal2', '[email protected]', "michalpassword2")
assert Profile.objects.count() == User.objects.count()
#get token for first_user
token_url = reverse('token_obtain_pair')
login_data = {
"username": first_user.username,
"password": "michalpassword"
}
token = api_client.post(token_url, login_data, format='json')
api_client.credentials(HTTP_AUTHORIZATION='Bearer ' + token.data['access'])
# now update second_user Profile with first_user token
profile_url = reverse('profile-detail', args=[second_user.id])
response = api_client.get(profile_url)
bio_data = {
"user": response.data['user'],
"bio": "This is test user",
"location": "Wroclaw"
}
response = api_client.put(profile_url, bio_data, format='json')
assert response.status_code == 403
pytest
로 이 테스트를 다시 실행합시다. 이제 두 번째 테스트가 실패했습니다. 왜냐하면 우리는 우리를 제외한 다른 프로필을 업데이트할 수 있기 때문입니다!FAILED restapi/tests.py::test_user_should_not_be_able_to_update_other_profile - assert 200 == 403
단계 5 - 테스트에서 발견된 오류 수정
코드에서 이 버그를 복구해야 합니다. (이것은 보안 버그입니다.)우선, 우리는
permissions.py
파일을 추가하고 그 중에서 적당한 권한 논리를 만듭니다.from rest_framework import permissions
class IsProperUserOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the User linked with the Profile.
return obj.user == request.user
그리고 우리는 이 논리를 포함하기 위해 우리의 ProfileViewSet
에서 views.py
를 변경할 수 있다.새로 만든 권한을 가져오는 것을 잊지 마십시오.from .permissions import IsProperUserOrReadOnly
# some code here
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsProperUserOrReadOnly]
지금 우리는 pytest
로 다시 테스트를 실행할 수 있다. 우리는 반드시 테스트를 통과해야 한다.간단하게:)6단계- Github 작업을 생성하여 마스터 브랜치에 대한 각 pull 요청을 확인합니다.
테스트가 통과되면 GitHub 및 GitHub 작업을 설정할 수 있습니다.저장소가 모든 컨텐츠를 직접
master
지점으로 전송하는 것을 차단합니다."설정"-> "분기"로 들어가 초보자를 위한 분기 정책을 추가할 수 있습니다.분기 이름 모드에서 "master"를 입력하고 "합병하기 전에 심사 요청"을 선택하십시오.
그리고 Github repo의 작업으로 이동하여 Python 응용 프로그램을 추가합니다. 이것은 첫 페이지에서 건의해야 합니다.
이것은 디렉터리
python-app.yml
에 yaml 파일 .github/workflows/
을 추가합니다.우리의 파일은 다음과 같이 해야 한다.# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Python application
on:
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest
단계 8 - Github 작업에서 구문 사용하기
로컬에서 만든 지점에서 테스트를 중단하고 다음을 수행합니다.
git pull
git checkout -b feature/broken-test
tests.py
의 마지막 줄을 403에서 200으로 변경합니다.assert response.status_code == 200
이제 코드를 추가, 제출 및 푸시하고 Github 작업을 트리거하는 요청을 만들 수 있습니다.이 코드를 분기로 전송한 후 Github 저장소 페이지에서 Pull 요청을 작성합니다."pytest 테스트"단계의 오류를 GitHub 작업에서 보았어야 합니다.
로그는 다음과 같이 표시됩니다.
> assert response.status_code == 200
E assert 403 == 200
E + where 403 = <Response status_code=403, "application/json">.status_code
restapi/tests.py:79: AssertionError
------------------------------ Captured log call -------------------------------
WARNING django.request:log.py:224 Forbidden: /api/v1/profile/2/
이러한 오류는 Pull 요청 뷰로 채워지고 "모든 검사 실패"를 표시합니다.이것은 변경 사항을 master
지점에 통합하지 말라는 좋은 경고입니다.tests.py
의 마지막 줄을 복구하고 상태 403을 다시 기대하며 코드를 다시 전송합니다.이제 테스트가 동작을 전달하고 있는 것을 보아야 합니다. 이제 마스터에 안전하게 통합할 수 있습니다. (pull 요청도 보기를 업데이트합니다.)다음:
Reference
이 문제에 관하여(Django, DRF, JWT 및 OpenApi를 사용하여 적절한 RESTAPI 테스트 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/misiekofski/create-proper-rest-api-with-django-drf-jwt-and-openapi-testing-2o16텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)