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_dbdecorator는 테스트에서 깨끗한 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.)