❗ 문제 설명
모듈 테스트 코드를 작성하는 과정에서, 예외 처리 누락·검증 누락·타입 불일치로 보이는 버그 6건을 발견했습니다.
- member 정보 수정 중 무결성 오류 처리가 AttributeError로 죽음
- notice hard delete가 삭제 상태를 체크하지 않음
- chat 1:1 채팅방 생성 시 project_id 검증 누락
- Work의 start_date/end_date가 timezone 정보 없이 저장됨
- Project의 start_date/end_date가 timezone 정보 없이 저장됨
- project 초대 거절(decline)이 만료 여부를 체크하지 않음 (수락과 비대칭)
🔁 재현 방법
-
PATCH /members/{id} 호출 시 DB에서 IntegrityError가 나는 상황을 만들면 (예: 유니크 제약 위반), MemberService.update의 예외 처리 블록이 MemberUpdateIn에 없는 data.email을 참조하다 AttributeError 발생.
-
is_deleted=False인 공지에 대해 NoticeService.delete(notice_id, hard=True) 호출 → 상태 체크 없이 바로 hard delete 수행됨.
-
POST /chat/projects/{project_id}/rooms/direct 호출 시 body의 project_id를 경로의 project_id와 다르게 보내도 검증 없이 그대로 처리됨.
-
Work 생성 시 start_date/end_date에 timezone 정보가 포함된 값 (예: "2026-01-01T00:00:00+09:00")을 넣으면 asyncpg.exceptions.DataError 발생.
-
Project 생성 시 동일한 방식으로 timezone 포함 값을 넣으면 동일한 DataError 발생.
-
만료된 초대 토큰으로 POST /project/invite/decline 호출 → 만료 여부와 상관없이 정상 DECLINED 처리됨.
✅ 기대 동작
- create()와 동일하게 AppError.bad_request(400)로 변환되어야 함
- hard delete 전에 is_deleted가 True인지 확인하고, 아니면 bad_request(400)
- body와 path의 project_id가 다르면 bad_request(400) (notice/work의 create와 동일)
- 다른 datetime 필드들처럼 timezone-aware 값도 정상 저장되어야 함
- 4번과 동일
- accept와 동일하게 만료된 초대는 EXPIRED로 전환하고 bad_request(400)
🧩 환경 정보
- Python 3.12, FastAPI 0.129, SQLAlchemy 2.0 / SQLModel, PostgreSQL 16
- 로컬과 CI 양쪽에서 동일하게 재현됨
❗ 문제 설명
모듈 테스트 코드를 작성하는 과정에서, 예외 처리 누락·검증 누락·타입 불일치로 보이는 버그 6건을 발견했습니다.
🔁 재현 방법
PATCH /members/{id} 호출 시 DB에서 IntegrityError가 나는 상황을 만들면 (예: 유니크 제약 위반), MemberService.update의 예외 처리 블록이 MemberUpdateIn에 없는 data.email을 참조하다 AttributeError 발생.
is_deleted=False인 공지에 대해 NoticeService.delete(notice_id, hard=True) 호출 → 상태 체크 없이 바로 hard delete 수행됨.
POST /chat/projects/{project_id}/rooms/direct 호출 시 body의 project_id를 경로의 project_id와 다르게 보내도 검증 없이 그대로 처리됨.
Work 생성 시 start_date/end_date에 timezone 정보가 포함된 값 (예: "2026-01-01T00:00:00+09:00")을 넣으면 asyncpg.exceptions.DataError 발생.
Project 생성 시 동일한 방식으로 timezone 포함 값을 넣으면 동일한 DataError 발생.
만료된 초대 토큰으로 POST /project/invite/decline 호출 → 만료 여부와 상관없이 정상 DECLINED 처리됨.
✅ 기대 동작
🧩 환경 정보