[백엔드] pytest testcode 개편
오늘은.. 미루고 미뤄왔던 pytest testcode 를 예쁘게 바꿔볼 예정이다.
어제 fat model 도 끝냈겠다.. 이젠 pytest 를 좀 더 눈에 딱 띄고 예쁘게 해볼 예정이다.
일단 해야 할 것은 다음과 같다.
1. 코드가 300줄 이상이므로.. 좀 더 작게 파일로 나누기
2. 완벽히 하드코딩 되어있으므로 변수로 넣는 방식을 사용할 수 있도록 할 것
3. 2의 경우와 마찬가지 이지만 일단 order 의 경우에 다른 order 를 써도 백엔드상에서 가능해야 하므로..
4. mock 객체와 fixture, util function 등등을 잘 사용해서 예쁘게 잘 딱 바꿔보자
일단 fixture 를 먼저 밖으로 빼놓았다.
파일을 생성하기 전에 귀찮은 일을 제외하고 싶었기 때문이다.
import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse
from rest_framework.test import APIClient
from todos.models import Category, Todo
User = get_user_model()
client = APIClient()
@pytest.fixture
def create_user(db):
user = User.objects.create_user(
username="testuser",
email="testuser@example.com",
password="testpassword",
)
return user
@pytest.fixture
def authenticated_client(create_user):
client.force_authenticate(user=create_user)
yield client
client.force_authenticate(user=None) # logout
@pytest.fixture
def create_category(db, create_user):
category = Category.objects.create(
user_id=create_user,
title="Test Category",
color="#FFFFFF",
order="0|hzzzzz:",
)
return category
이런식으로 모든 fixture 가 파일마다 있었는데 이걸 conftest.py 파일을 만들고 그 안에 작성했다.
# This file is for Pytest Configuration
# This file is used to define fixtures that can be used in multiple test files
import pytest
from rest_framework.test import APIClient
from todos.models import Category, SubTodo, Todo, User
client = APIClient()
@pytest.fixture
def create_user(db):
user = User.objects.create_user(
username="testuser",
email="testuser@example.com",
password="testpassword",
)
return user
@pytest.fixture
def authenticated_client(create_user):
client.force_authenticate(user=create_user)
yield client
client.force_authenticate(user=None) # logout
@pytest.fixture
def create_category(db, create_user):
category = Category.objects.create(
user_id=create_user,
title="Test Category",
color="#FFFFFF",
order="0|hzzzzz:",
)
return category
@pytest.fixture
def create_todo(db, create_user, create_category):
todo = Todo.objects.create(
user_id=create_user,
start_date="2024-08-01",
end_date="2024-08-30",
category_id=create_category,
content="Test Todo",
order="0|hzzzzz:",
is_completed=False,
)
return todo
@pytest.fixture
def create_subtodo(db, create_user, create_todo):
subtodo = SubTodo.objects.create(
content="Test SubTodo",
date="2024-08-01",
todo=create_todo,
order="0|hzzzzz:",
is_completed=False,
)
return subtodo
이런식으로 넣으니 위에 있던 @fixture 부분을 전부 제거하고 model을 import 하는 부분도 테스트의 주가 아닌 모델들을 전부 지울 수 있었다.
faker 공부
간단했다. 의미 없는 값을 넣어줄 수 있는 함수였다.!
https://pypi.org/project/Faker/
일단 적용해봤다.
@pytest.mark.django_db
def test_create_todo_success(
authenticated_client, create_category, create_user
):
url = reverse("todos")
data = {
"user_id": create_user.id,
"start_date": "2024-08-01",
"end_date": "2024-08-02",
"content": "Test Todo",
"category_id": create_category.id,
"order": "0|hzzzzz:",
}
response = authenticated_client.post(url, data, format="json")
assert response.status_code == 201
assert "id" in response.data
여기에서 start_date, end_date, content 는 어떤 것을 넣어도 상관없다! (물론 start가 end 보다 앞서거나 같기만 하면 된다)
일단 투두에 넣어봤다.
fixture 로 date 와 content 를 불러 올 수 있도록 작성한 후에 이를 테스트에 넣도록 코드를 수정했다.
conftest.py
@pytest.fixture
def date():
return fake.date_this_year()
@pytest.fixture
def content():
return fake.sentence(nb_words=6)
# test.py
@pytest.mark.django_db
def test_create_todo_success(
authenticated_client, create_category, create_user, date, content
):
url = reverse("todos")
data = {
"user_id": create_user.id,
"start_date": date,
"end_date": date + timedelta(days=1),
"content": content,
"category_id": create_category.id,
"order": "0|hzzzzz:",
}
response = authenticated_client.post(url, data, format="json")
assert response.status_code == 201
assert "id" in response.data
일단 이런식으로 작성했다.
그리고 코파일럿에게 이런식으로 수정해달라고했는데, 잘 된줄 알았는데 pytest 를 돌렸더니 못보던 에러가 발생해서 내일 다시 해봐야겠다...
mock 객체에 대해서 공부하기
https://codguide.tistory.com/8
[Python] 파이썬 유닛 테스트 pytest-mock 사용법
python으로 유닛테스트를 작성하다 보면 제약사항이 생길 수 있습니다. 예를 들어, 방화벽으로 외부망이 금지된 환경에서 테스트를 해야 하거나, 실제 운영환경이 갖추어지지 않은 곳에서 테스트
codguide.tistory.com
이 블로그를 통해서 이해할 수 있었다.
일단 내가 작성한 pytest 중에 다른 곳에서 반응을 받아오는 게 따로 있는지.. 좀 고민을 해봐야할 것 같다.
일단은 faker 를 가장 먼저 도입하고 mock 은 이 이후에 해봐야겠다.
확실히 어제.. 너무 늦게 자서 오늘 아무것도 못하는 걸보니.. 그냥 1시 이후에는 하던 작업 멈추고 내일 하도록 해야겠다...