8주차 과제 체크포인트
기본 과제
필수
- 반복 유형 선택
- 일정 생성 또는 수정 시 반복 유형을 선택할 수 있다.
- 반복 유형은 다음과 같다: 매일, 매주, 매월, 매년
- 31일에 매월을 선택한다면 -> 매월 마지막이 아닌, 31일에만 생성하세요.
- 윤년 29일에 매년을 선택한다면 -> 29일에만 생성하세요!
- 반복 일정 표시
- 캘린더 뷰에서 반복 일정을 시각적으로 구분하여 표시한다.
- 아이콘을 넣든 태그를 넣든 자유롭게 해보세요!
- 캘린더 뷰에서 반복 일정을 시각적으로 구분하여 표시한다.
- 반복 종료
- 반복 종료 조건을 지정할 수 있다.
- 옵션: 특정 날짜까지, 특정 횟수만큼, 또는 종료 없음 (예제 특성상, 2025-10-30까지)
- 반복 일정 단일 수정
- 반복일정을 수정하면 단일 일정으로 변경됩니다.
- 반복일정 아이콘도 사라집니다.
- 반복 일정 단일 삭제
- 반복일정을 삭제하면 해당 일정만 삭제합니다.
선택
- 반복 간격 설정
- 각 반복 유형에 대해 간격을 설정할 수 있다.
- 예: 2일마다, 3주마다, 2개월마다 등
- 예외 날짜 처리:
- 반복 일정 중 특정 날짜를 제외할 수 있다.
- 반복 일정 중 특정 날짜의 일정을 수정할 수 있다.
- 요일 지정 (주간 반복의 경우):
- 주간 반복 시 특정 요일을 선택할 수 있다.
- 월간 반복 옵션:
- 매월 특정 날짜에 반복되도록 설정할 수 있다.
- 매월 특정 순서의 요일에 반복되도록 설정할 수 있다.
- 반복 일정 전체 수정 및 삭제
- 반복 일정의 모든 일정을 수정할 수 있다.
- 반복 일정의 모든 일정을 삭제할 수 있다.
심화 과제
- 이 앱에 적합한 테스트 전략을 만들었나요?
각 팀원들의 테스트 전략은?
페어팀(2팀, 6팀)끼리 각자 해당 테스트 종류별로 어떤 상황에 쓰는지 얘기해보고 이번 프로젝트에는 어떤 테스트 전략이 필요한지 얘기 나눴습니다. 여기서도 "간단한 일정 추가 프로젝트에 E2E는 과하다" 는 의견과 "일정 추가는 사용자가 직접 체험하는 핵심 기능이라 실제 브라우저에서의 동작이 중요하니 E2E해봐도 좋다"는 의견이 나왔습니다. 시각적 회귀 테스트는 논외였습니다.(너무 과함)
- 유닛: 반복일정, 날짜 관련 유틸 테스트 무조건 필요 (반대의견 없음)
- 통합: hooks 나 비지니스 로직 검증 필요 (반대의견 없음)
- E2E
- E2E 테스트는 사용자의 실제 경험을 가장 잘 대변하기 때문에, 다른 테스트로는 발견하기 어려운 치명적인 버그를 잡는 데 효과적
- 제일 핵심적인 플로우를 한번에 검증하는게 좋을거같음
- (반대) 과하지 않나? 백엔드 측에서 추가한 API에 대한 통합 테스트 반복일정에 대한 수정, 생성, 삭제 정도면 충분
- 시각적 회귀:
- 전체적인 UI 테스트한번은 필요할 것 같음
- (반대) 과함. 소규모 프로젝트나 UI 변경이 잦지 않은 경우에는 수동으로 검수하는 것이 더 효율적
전체적인 의견을 정리해보면 피라미드 전략이 될거같습니다.. 유닛 많이 통합 적당히 E2E 조금
결론
테스트 전략 논의 및 시나리오 세웠으니 의견 맞는 사람끼리 팀으로 짜거나 개별로 테스트 작성하기
합의된 테스트 전략과 그 이유는 무엇인가요?
이번 프로젝트에서는 통합 테스트와 E2E(End-to-End) 테스트를 병행하는 전략을 선택했습니다. 도은님, 소연님과 함께 통합 테스트 시나리오 3개 중 1개, E2E 테스트 시나리오 3개 중 1개를 각각 선택해 구현하는 방식으로 진행했습니다.
-
통합 테스트 보완 기존에 작성된 통합 테스트는 주로 개별 기능 단위의 검증에 초점이 맞춰져 있었습니다. 실제 사용 흐름에서 필요한 조합이나 예외 상황을 다룰 수 있도록 보충 시나리오를 직접 작성해 테스트를 추가했습니다.
-
E2E 테스트의 필요성 단위 또는 통합 테스트만으로는 전체 사용자 흐름이나 상태 변화, 뷰 간 전환 등의 맥락을 충분히 검증하기 어렵다고 생각합니다. 특히 이번 프로젝트는 사용자의 연속적인 행동과 일정한 흐름에 따라 작동하는 캘린더 앱이기 때문에, 실제 사용자 경험을 기준으로 한 검증이 필수적이라 생각해 E2E 테스트를 추가했습니다.
결론
통합 테스트는 기능별 정확성을 빠르게 검증하는 데 효과적이며, E2E 테스트는 전체 사용자 경험을 보장하는 데 필수적인 전략이라 생각됩니다. 사용자 경험이 핵심인 캘린더 앱 특성상, 두 테스트 방식이 서로를 보완하며 프로젝트의 완성도를 높여준다고 판단했습니다!
추가로 작성된 테스트 코드는 어떤 것들이 있나요?
!!심화에서 추가된 테스트 코드는 3명(이태영, 정도은, 박소연) 전부 동일하게 작성했습니다.
통합테스트
E2E
CI에 어..어떻게 추가하는 겁니까! 완성도 있게 적용해서 통과 체크 표시를 얻지는 못 했지만 그래도 새벽 내내 고생해서 해본 결과물을 자랑이라도 노력상이라도 알리고자 올립니다.
과제 셀프회고
기술적 성장
이번 과제를 통해 정말 많은 것을 배웠습니다. 특히 TDD 방식을 RED->GREEN->REFACTORING 순서로 처음부터 끝까지 체계적으로 적용해보면서, 테스트 먼저 작성하고 구현하기가 얼마나 나에겐 어려운지 하지만 의미있는 개발 방법인지 직접 체감할 수 있었습니다.
가장 기억에 남았던 상황은 반복 일정 로직을 구현할 때였습니다. 31일이 없는 달이나 윤년 같은 예외 상황들을 처리하면서 단순한 날짜 계산이 얼마나 복잡할 수 있는지 깨달았습니다. 처음에는 "그냥 날짜에 +1 하면 되겠지"라고 생각했는데 실제로 구현해보니 엄청나게 많은 엣지 케이스가 있었습니다.
테스트 피라미드, 테스트 트로피 개념도 이번에 이해하게 됐습니다. 두 가지 개념에 대해 간략하게 생각하는 내용을 적어 보았습니다.
테스트 피라미드: 단위 테스트는 빠르고 정확하지만, 통합 테스트는 실제 사용 패턴을 검증할 수 있고, E2E 테스트는 사용자 관점에서 전체 플로우를 확인할 수 있다는 걸 직접 경험하면서 각각의 역할과 중요성을 알게 되었습니다. 비중은 단위 테스트 > 통합 테스트 > E2E 테스트 순으로 비중이 높았습니다.
테스트 트로피: 단위 테스트(빠르고 안정적) → 통합 테스트(실제 환경과 유사) → E2E 테스트(사용자 시나리오) → 수동 테스트(창의적 탐색) 순으로 구성되는데, 각 단계가 서로 보완하면서 전체적인 품질을 보장한다는 것을 알았습니다. 테스트 피라미드의 한계를 극복하고, 특히 프런트엔드 개발에 더 적합한 테스트 접근 방식이라고 하는데 아마 이번 프로젝트에서는 MSW로 실제와 비슷한 환경을 구성한 조건에서 단위 테스트의 비중보다는 통합 테스트/E2E 테스트의 비중을 높혀 실제 작동 여부와 실 사용에 대한 시나리오 검증하는 쪽에 더 목적이 있다고 생각하였습니다.
MSW와 Playwright도 과제를 하면서 직접 코드 작성해서는 처음 써봤는데, MSW로 API 모킹하는 게 생각보다 어렵지만 지난 주차 내용을 참고해서 이번에 해보니까 할 수 있었습니다. Playwright로 실제 브라우저에서 테스트하는 건 처음 이였는데 실제 되는지 의문이 드는 마무리였지만 의미 있었습니다. 특히 E2E 테스트가 실패할 때 스크린샷을 보면서 "아, 이 부분에서 문제가 생겼구나"라고 바로 파악할 수 있어서 디버깅이 훨씬 쉬웠습니다.
코드 품질
만족스러운 부분은 repeatEventUtils.ts의 generateRepeatEvents 함수를 깔끔하게 분리한 것입니다. 처음에는 App.tsx에 모든 로직을 다 넣으려고 했는데, 테스트를 먼저 작성하면서 "이 로직은 분리해야겠다"는 생각이 들어서 결과적으로 복잡한 반복 로직이 하나의 함수에 잘 정리되었고 나중에 수정할 때도 훨씬 편했습니다.
반복 일정 아이콘 시스템도 이게 맞나? 하면서 이 부분은 웃으면서 구현했던 기억이 있습니다. 🔄 📋 📊 🎯 이런 이모지를 사용해서 매일/매주/매월/매년을 구분했는데, 시각적으로도 예쁘고 사용자도 쉽게 구분할 수 있을 것 같아 만족하며 처리 했습니다. 하지만 이 이모지 하나만 바꾸면 전체 테스트는 다 통과 안되는데... 이런 부분은 어떻게 테스트와 개발 코드와의 의존성은 낮출 수 있을까 싶습니다.
테스트 격리도 나름 ? 잘 된 것 같습니다. MSW를 사용해서 각 테스트가 독립적으로 실행되도록 했는데, 이게 정말 중요하다는 걸 느꼈습니다. 순서를 바꾸거나 그래도 다른 테스트에 영향을 주지 않으니까 나의 문제점이 여기저기 전파 되지 않았습니다. ㅎㅎ
하지만 아직 개선할 부분도 있는데 App.tsx가 애초에 모든 코드가 몰려 있고 복잡한 상황인데 이 부분을 코드 분리를 진행하고 했어야 하는데 커스텀 훅으로 더 분리하면 좋을 것 같은데, 시간이 부족해서 못했습니다.
반복 일정 수정/삭제도 현재는 단일 처리만 지원하는데, 기본 추가 과제인 전체 수정/삭제 기능도 추가하면 좋을 것 같아요. 하지만 기본 요구사항은 충족했으니까 일단은 만족스럽습니다.
개발하면서 몇 가지 헤맨 부분들도 있었습니다. 가장 어려웠던 건 단일 일정 생성과 반복 일정 생성 로직을 정확히 분리하는 거였어요. 처음에는 하나의 함수에서 모든 걸 처리하려고 했는데, 테스트를 작성하면서 "이건 분리해야겠다"는 생각이 들었어요. 결국 generateRepeatEvents 함수로 분리했지만, 처음부터 이렇게 설계했으면 더 깔끔했을 것 같아요.
통합 테스트를 작성할 때도 문제가 있었어요. 시나리오가 복잡해지면서 테스트 실행 시간이 5초를 넘어가면 자동으로 실패하는 문제가 생겼어요. setupTests.ts에서 타임아웃을 30초로 늘려서 해결했는데, 이게 올바른 해결책인지 궁금해요. 아니면 테스트를 더 작은 단위로 나누는 게 좋을까요?
또 하나는 반복 일정 체크박스가 기본적으로 체크되어 있는 상태인데, useState의 초기값이 'none'으로 되어 있어서 단일 일정과 반복 일정 생성 시 혼란스러웠어요. 이 부분도 개선이 필요할 것 같습니다.
학습 효과 분석
가장 큰 배움은 당연히 TDD 방식의 실제 적용이였습니다. 이론으로만 알고 있던 걸 실제로 해보니까, 테스트를 먼저 작성하는 게 얼마나 코드 품질과 설계에 도움이 되는지 직접 느낄 수 있었습니다. 하지만 테스트를 먼저 작성해도 결국 설계에 맞게 테스트를 고쳐버리면 이게 의미가 있나? 싶은 생각도 많이 들었지만 "이 기능이 어떻게 동작해야 하는지"를 생각하고 테스트로 표현하는 과정에서 요구사항을 계속적으로 생각하고 구현을 하게 되고 있는 제 모습을 발견 했습니다.
복잡한 비즈니스 로직을 테스트하는 방법도 꽤나 많은 고민을 통해 배웠습니다. 날짜 계산 같은 건 엣지 케이스가 정말 많은데, 체계적으로 테스트 케이스를 작성한다면 놓칠 수 있는 부분들을 하나하나 잡아낼 수 있겠다 생각이 들었습니다. 실제로 이번 과제에서는 많이 하지 못했지만요.
아직 부족한 부분도 참 많이 남았는데요. 하하 성능 최적화는 거의 신경 쓰지 못했는데, 대량의 반복 일정을 생성할 때 실제로는 어떻게 처지하는지 궁금했습니다. 그래서 휴대폰 캘린더와 노션 캘린더를 찾아 보았었는데 아래와 같은 로직이 많았습니다.
지금은 그냥 2025년 10월 30일까지 제한을 걸고 작업하긴 했지만 실제로는 어떻게 하면 될지? 생각을 해봤었습니다. 단일 일정 / 반복 일정을 1일 1주 1개월 1년 마다 / 계속 반복, 일정 반복 횟수 설정, 종료 날짜 설정 해서 더 디테일하게 나눠서 하는 것은 이해 했는데 계속 반복으로 2100년까지 매일 설정하면 이 부분에서 대량의 데이터 처리를 어떻게 다룰까? 궁금점이 남았습니다.
실무에서는 이번에 배운 테스트 전략 수립 능력이 정말 많이 유용할 것 같아요. 사실 실제로 적용 할 날이 올까? 생각이 들긴 하지만 만약 적용을 한다면 프로젝트의 특성에 맞는 테스트 계획을 세우고, TDD를 통한 구현 할 때 안전한 기능 개발 방법을 적용할 수 있겠다 생각을 했습니다.
과제 피드백
이번 주차 과제 개인적으로 너무 힘들었는데(사실 안 힘든 주차가 없다) 간단하게 제가 느낀 점을 적어 보았습니다.
- TDD 강제(?) 적용: TDD 방식이라는 것으로 고정을 하고 진행을 하니까 처음에는 부담스럽고 이렇게 하는게 맞나? 그리고 결국 그냥 RED 단계 와장창 작성하고 GREEN 처리하고 그런식으로 된 부분도 있지만 결과적으로 코드 품질과 설계가 크게 향상되었다고 생각합니다. 리팩토링을 하거나 실제 구현 된 부분에서 잘 못 된 부분이라고 생각하는 부분을 많이 고쳤습니다.
- 실제 비즈니스 로직 구현: 위에 내용에서 계속 말을 해서 이젠 너무 많이 이야기 한 것 같은데 날짜 계산, 반복 로직 같은 복잡한 도메인 로직을 직접 구현해보면서 엣지 케이스의 중요성을 깨달았습니다. 직접적으로 로직 구현을 한 부분이 이 부분이 너무 강렬하게 머릿속에 남았나 봅니다.
- 다양한 테스트 방식 체험: 단위/통합/E2E 테스트를 모두 경험해보면서 각각의 역할과 어떻게 구성 하는지를 알게 되었습니다.
리뷰 받고 싶은 내용
-
상태 관리 초기값 설계: 반복 일정 체크박스가 기본적으로 체크되어 있는 상태인데
useState의 초기값이'none'으로 되어 있어서 생성 수정 할 때 문제가 발생하여 저는 초기값에 맞게 화면상에서도 체크를 해제하고 구현을 진행 했습니다. 이런 상태 불일치 문제를 해결하는 방법은 어떻게 하면 될까요? -
통합 테스트 시나리오를 작성하고 테스트 실행을 하는데 5초가 넘게 되면 테스트가 실패하는 문제에 대한 해결법이 궁금합니다. 저는 이번 프로젝트에서는 setupTests 에서 일단 시간을 늘려주고 했는데 올바른 방법은 아닌 것 같다는 생각이 듭니다.
-
이번 과제에서 테스트 코드 비율은 아래와 같은데
파일 개수 기준
- 단위 테스트: 8개 파일
- 통합 테스트: 7개 파일 (hooks 포함)
- E2E 테스트: 3개 파일 비율: 단위 44% : 통합 39% : E2E 17%
코드 라인 기준 (대략적)
- 단위 테스트: ~1,243줄
- 통합 테스트: ~1,508줄
- E2E 테스트: ~182줄 비율: 단위 42% : 통합 51% : E2E 7%
이러한 비율이 어떤 부분? 에서 기준이 되는 걸까요? 이상적인 비율: 단위 70% : 통합 20% : E2E 10% 이라는데 이 비율의 기준이 쓸대없을 수 있지만 궁금했습니다.
과제 피드백
안녕하세요 태영님! 체계적인 회고가 인상적이네요 ㅎㅎ 고생하셨습니다!!
가장 기억에 남았던 상황은 반복 일정 로직을 구현할 때였습니다. 31일이 없는 달이나 윤년 같은 예외 상황들을 처리하면서 단순한 날짜 계산이 얼마나 복잡할 수 있는지 깨달았습니다. 처음에는 "그냥 날짜에 +1 하면 되겠지"라고 생각했는데 실제로 구현해보니 엄청나게 많은 엣지 케이스가 있었습니다.
맞아요. 테스트를 작성하다보면 자연스럽게 다양한 엣지케이스에 대해 생각하게 된답니다 ㅎㅎ 반대로, 테스트를 작성하는 것보다 중요한건 결국 스펙을 구체화하는 행위라고 생각해요! 테스트는 이를 코드로 승화시킨 과정인거죠.
상태 관리 초기값 설계: 반복 일정 체크박스가 기본적으로 체크되어 있는 상태인데 useState의 초기값이 'none'으로 되어 있어서 생성 수정 할 때 문제가 발생하여 저는 초기값에 맞게 화면상에서도 체크를 해제하고 구현을 진행 했습니다. 이런 상태 불일치 문제를 해결하는 방법은 어떻게 하면 될까요?
체크박스를 컴포넌트로 분리한 다음에 defaultValue로 받아오는거죠 ㅎㅎ
useState(props.chekced ?? "none") 이런 느낌..?
근데 이미 그렇게 해주신 것 같네요 ㅋㅋ 훅으로 분리하면 조금 더 깔끔하게 해결할 수 있답니다!
통합 테스트 시나리오를 작성하고 테스트 실행을 하는데 5초가 넘게 되면 테스트가 실패하는 문제에 대한 해결법이 궁금합니다. 저는 이번 프로젝트에서는 setupTests 에서 일단 시간을 늘려주고 했는데 올바른 방법은 아닌 것 같다는 생각이 듭니다.
말씀해주신 것 처럼 timeout을 늘리는 방법도 있고... 이보다 중요한건 실패 원인을 찾아내는거라고 생각해요 ㅎㅎ 5초 이상 걸리는건 문제가 분명 있어보이네요..! 통합 테스트의 경우 실제 브라우저 환경이 아니기 때문에 더 빠르게 실행되어야 하는게 정상일거라서, 문제의 원인을 분석해보시는걸 추천드려요!
테스트코드 비율이 어떤 부분? 에서 기준이 되는 걸까요? 이상적인 비율: 단위 70% : 통합 20% : E2E 10% 이라는데 이 비율의 기준이 쓸대없을 수 있지만 궁금했습니다.
흠... 저는 아예 비율 자체를 신경쓰지 않는 편이라서요 ㅎㅎ.. 이런 고민을 해본적이 없네요.. ㅠㅠ 다만 비율을 코드라인으로 따지기보단 요구사항이나 테스트 커버리지를 기준으로 측정해보는걸 추천드려요!