Skip to content

Commit

Permalink
a
Browse files Browse the repository at this point in the history
  • Loading branch information
YSHyeonn committed Feb 23, 2024
2 parents 2453530 + e593494 commit aa4c7d7
Show file tree
Hide file tree
Showing 14 changed files with 448 additions and 13 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ jobs:
DJANGO_ALLOWED_HOSTS: ${{ secrets.DJANGO_ALLOWED_HOSTS }}
run: |
cd app
python manage.py makemigrations --settings=cspc_web.settings_dev
python manage.py migrate --settings=cspc_web.settings_dev
python manage.py test --settings=cspc_web.settings_dev
python manage.py makemigrations
python manage.py migrate
python manage.py test
29 changes: 29 additions & 0 deletions app/Dockerfile-dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM python:3.8.13

# 환경 변수 설정
ENV HOME=/home/app
ENV APP_HOME=/home/app/web


# 애플리케이션 디렉터리 생성
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

# 파이썬 실행 관련 환경 변수
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# requirements.txt 복사 및 설치
COPY ./requirements.txt $APP_HOME/requirements.txt
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir --upgrade -r requirements.txt

# .env 파일을 제외하고 모든 파일 복사
COPY . $APP_HOME
RUN rm -f $APP_HOME/.env

RUN sed -i 's/\r$//g' $APP_HOME/entrypoint-dev.sh

RUN chmod +x $APP_HOME/entrypoint-dev.sh

ENTRYPOINT [ "/home/app/web/entrypoint-dev.sh" ]
234 changes: 234 additions & 0 deletions app/apply/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
from datetime import timedelta
import datetime
from unittest.mock import patch
from django.test import TestCase
from django.contrib.auth.models import User
from django.urls import reverse
from user.models import Applicant
from django.utils import timezone
from rest_framework.test import APIClient
from apply.models import (
InterviewTime,
RecruitProcess,
Recruitment,
Resume,
InterviewPlace,
)


class GetResultAPITest(TestCase):
def setUp(self):
# 'APPLY' 상태의 Recruitment 인스턴스 생성
# start_time, document_deadline 등 필요한 필드 값 설정
start_time = timezone.now().date() - timedelta(days=1) # 어제 시작
document_deadline = timezone.now().date() + timedelta(days=1) # 내일 마감
announce_middle_time = timezone.now() + timedelta(days=2)
interview_start_time = timezone.now().date() + timedelta(days=3)
interview_end_time = timezone.now().date() + timedelta(days=4)
announce_final_time = timezone.now() + timedelta(days=5)

self.recruitment = Recruitment.objects.create(
year=2023,
term="Spring",
start_time=start_time,
document_deadline=document_deadline,
announce_middle_time=announce_middle_time,
interview_start_time=interview_start_time,
interview_end_time=interview_end_time,
announce_final_time=announce_final_time,
process=RecruitProcess.APPLY,
)
self.client = APIClient()
self.user = Applicant.objects.create_user(
student_id="testuser", password="tmppassword"
)

self.interview = InterviewTime.objects.create(
time="2024-02-20 10:00:00", is_fixed=True
)

# InterviewPlace 인스턴스 생성
interview_place = InterviewPlace.objects.create(place="새로운 면접 장소")

self.resume = Resume.objects.create(
applicant=self.user,
phone="01011112222",
name="홍길동",
semester=2,
introduce="hi",
motivate="cspc is the best",
to_do="MT",
etc="etc",
interview_requirement="nothing",
interview_place=interview_place,
updated_at=(timezone.now() + timedelta(days=1)).isoformat(),
fixed_interview_time=(timezone.now() + timedelta(days=30)).isoformat(),
created_at=timezone.now().isoformat(),
is_pass_document=True,
is_pass_final=False,
)
# interview_time_choice 필드에 대한 관계는 따로 설정
# interview_time_choices = InterviewTime.objects.filter(id__in=[0, 3])
interview_time_choices_ids = list(
InterviewTime.objects.filter(id__in=[2, 4]).values_list("id", flat=True)
)
self.resume.interview_time_choice.set(interview_time_choices_ids)

self.get_recuit_session_url = reverse("get_recuit_session")
self.get_interview_time_list_url = reverse("get_interview_time_list")
self.get_result_url = reverse("get_result")
self.resume_api_url = reverse("resume_api")
self.check_applicant_url = reverse("check_applicant")

# 로그인
self.client.force_authenticate(user=self.user)

def test_get_resume(self):
"""GET 요청으로 Resume 정보를 조회할 수 있는지 테스트하고 field 내용을 가지고 있는지 확인합니다."""
response = self.client.get(self.resume_api_url)
self.assertEqual(response.status_code, 200)

self.assertIn("name", response.data)
self.assertIn("semester", response.data)
self.assertIn("phone", response.data)
self.assertIn("interview_time_choice", response.data)

def test_create_resume(self):
"""POST 요청으로 새로운 Resume 정보를 생성할 수 있는지 테스트하고 field 내용을 가지고 있는지 확인합니다."""
interview_place2 = InterviewPlace.objects.create(place="알구일사")

# 올바른 InterviewTime ID 목록 확보
interview_time_ids = list(InterviewTime.objects.values_list("id", flat=True))

# 기존 Resume 데이터 삭제 후 user 정보 재사용
Resume.objects.filter(applicant=self.user).delete()

data = {
"applicant": self.user.id,
"phone": "01011112222",
"name": "홍길동",
"semester": 2,
"introduce": "hi",
"motivate": "cspc is the best",
"to_do": "MT",
"etc": "etc",
"interview_time_choice": interview_time_ids,
"fixed_interview_time": (timezone.now() + timedelta(days=30)).isoformat(),
"interview_requirement": "nothing",
"interview_place": interview_place2.id,
"created_at": timezone.now().isoformat(),
"updated_at": (timezone.now() + timedelta(days=2)).isoformat(),
"is_pass_document": True,
"is_pass_final": True,
}
response = self.client.post(self.resume_api_url, data, format="json")
self.assertEqual(response.status_code, 200)

self.assertIn("name", response.data)
self.assertIn("semester", response.data)
self.assertIn("phone", response.data)
self.assertIn("interview_time_choice", response.data)

def test_patch_resume(self):
"""PATCH 요청으로 기존 Resume 정보를 부분적으로 수정할 수 있는지 테스트합니다."""
patch_data = {
"introduce": "안녕하세요",
"motivate": "고기 먹고 싶어요",
"to_do": "회식하고 싶어요",
"name": "김서강",
} # 수정할 데이터
response = self.client.patch(self.resume_api_url, patch_data, format="json")
self.assertEqual(response.status_code, 200)
self.assertIn("introduce", response.data)
self.assertIn("motivate", response.data)
self.assertIn("to_do", response.data)
self.assertIn("name", response.data)
self.assertIn("applicant", response.data)

def test_get_result_authenticated(self):
"""
인증받은 결과이면 200을 반환하고 나머지 field 값들을 가지는지 확인합니다.
"""
# 로그인한 사용자 정보 확인
response = self.client.get(self.get_result_url)
self.assertEqual(response.status_code, 200)
self.assertIn("name", response.data)
self.assertIn("interview_place", response.data)

def tearDown(self):
# 인증 해제
self.client.force_authenticate(user=None)

def test_get_result_unauthenticated(self):
"""
인증받지 못한 결과이면 401을 반환하는지 확인합니다.
"""
# 명시적으로 인증 해제
self.client.force_authenticate(user=None)

response = self.client.get(self.get_result_url)
self.assertEqual(response.status_code, 401)

def test_get_recruit_session_with_existing_session(self):
"""
존재하는 채용 세션 데이터가 있으면 200을 반환하고 나머지 field 값들을 가지는지 확인합니다.
"""
response = self.client.get(self.get_recuit_session_url)
self.assertEqual(response.status_code, 200)

self.assertIn("year", response.data)
self.assertIn("term", response.data)
self.assertIn("start_time", response.data)
self.assertIn("document_deadline", response.data)
self.assertIn("announce_middle_time", response.data)
self.assertIn("interview_start_time", response.data)
self.assertIn("interview_end_time", response.data)
self.assertIn("announce_final_time", response.data)
self.assertIn("process", response.data)

@patch("apply.views.get_object_or_404")
@patch("apply.views.RecruitSerializer")
def test_get_recruit_session_check_process_called(
self, mock_serializer, mock_get_object_or_404
):
# Mock 객체를 설정합니다.
mock_recruitment = mock_get_object_or_404.return_value
mock_serializer_instance = mock_serializer.return_value
mock_serializer_instance.data = {
"year": 2024,
"term": "Spring",
"start_time": timezone.now().date() - timedelta(days=1),
"document_deadline": timezone.now().date() + timedelta(days=1),
"announce_middle_time": timezone.now() + timedelta(days=2),
"interview_start_time": timezone.now().date() + timedelta(days=3),
"interview_end_time": timezone.now().date() + timedelta(days=4),
"announce_final_time": timezone.now() + timedelta(days=5),
"process": RecruitProcess.CLOSE,
}
response = self.client.get(self.get_recuit_session_url)

# RecruitSerializer와 get_object_or_404가 올바르게 호출되었는지 확인합니다.
mock_get_object_or_404.assert_called_once_with(Recruitment)
mock_recruitment.check_process.assert_called_once()
self.assertEqual(response.status_code, 200)

self.assertIn("year", response.data)
self.assertIn("term", response.data)
self.assertIn("start_time", response.data)
self.assertIn("document_deadline", response.data)
self.assertIn("announce_middle_time", response.data)
self.assertIn("interview_start_time", response.data)
self.assertIn("interview_end_time", response.data)
self.assertIn("announce_final_time", response.data)
self.assertIn("process", response.data)

def test_get_interview_time_list_with_existing_data(self):
"""
존재하는 인터뷰 시간 데이터가 있으면 200 반환하는지, 인터뷰시간이 한개 이상 존재하는지, time을 가지는지 확인합니다.
"""
response = self.client.get(self.get_interview_time_list_url)
self.assertEqual(response.status_code, 200)
self.assertGreater(len(response.data), 0)

for item in response.data:
self.assertIn("time", item)
1 change: 1 addition & 0 deletions app/apply/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def post(self, request):
serializer.save()
return Response(serializer.data, status=200)
else:
print(serializer.errors)
return Response(
serializer.errors, status=400
) # 지원서 수정하는데 잘못 save되면 응답 & status #
Expand Down
8 changes: 8 additions & 0 deletions app/entrypoint-dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/sh


python manage.py makemigrations --settings=cspc_web.settings_dev
python manage.py migrate --no-input --settings=cspc_web.settings_dev


exec "$@"
5 changes: 5 additions & 0 deletions app/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Django==4.1.5
django-cors-headers==3.13.0
djangorestframework==3.14.0
drf-yasg==1.21.5
factory-boy==3.3.0
Faker==23.2.0
gunicorn==20.1.0
idna==3.4
inflection==0.5.1
Expand All @@ -16,12 +18,15 @@ Jinja2==3.1.2
MarkupSafe==2.1.2
openapi-codec==1.3.2
packaging==23.0
pillow==10.2.0
pycodestyle==2.10.0
python-dateutil==2.8.2
python-dotenv==0.21.1
pytz==2022.7.1
requests==2.28.2
ruamel.yaml==0.17.21
simplejson==3.18.3
six==1.16.0
sqlparse==0.4.3
uritemplate==4.1.1
urllib3==1.26.14
17 changes: 17 additions & 0 deletions app/user/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# user/factories.py

import factory
from django.contrib.auth import get_user_model
from faker import Faker

fake = Faker()
User = get_user_model()


class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = User

# 지원자를 위한 필드
student_id = factory.Sequence(lambda n: f"202415{n:02d}")
password = factory.PostGenerationMethodCall("set_password", "testpassword123")
20 changes: 20 additions & 0 deletions app/user/migrations/0003_alter_applicant_managers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.1.5 on 2024-02-14 22:57

from django.db import migrations
import user.models


class Migration(migrations.Migration):

dependencies = [
('user', '0002_alter_applicant_managers'),
]

operations = [
migrations.AlterModelManagers(
name='applicant',
managers=[
('objects', user.models.UserManager()),
],
),
]
2 changes: 1 addition & 1 deletion app/user/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Applicant(AbstractUser):
username = None
USERNAME_FIELD = "student_id"
REQUIRED_FIELDS = []
object = UserManager()
objects = UserManager()

def __str__(self):
return self.student_id
Expand Down
Loading

0 comments on commit aa4c7d7

Please sign in to comment.