Yangs1s 님의 상세페이지[5팀 양성진] Chapter 3-2. 프런트엔드 테스트 코드

8주차 과제 체크포인트

기본 과제

필수

  • 반복 유형 선택
    • 일정 생성 또는 수정 시 반복 유형을 선택할 수 있다.
    • 반복 유형은 다음과 같다: 매일, 매주, 매월, 매년
      • 31일에 매월을 선택한다면 -> 매월 마지막이 아닌, 31일에만 생성하세요.
      • 윤년 29일에 매년을 선택한다면 -> 29일에만 생성하세요!
  • 반복 일정 표시
    • 캘린더 뷰에서 반복 일정을 시각적으로 구분하여 표시한다.
      • 아이콘을 넣든 태그를 넣든 자유롭게 해보세요!
  • 반복 종료
    • 반복 종료 조건을 지정할 수 있다.
    • 옵션: 특정 날짜까지, 특정 횟수만큼, 또는 종료 없음 (예제 특성상, 2025-06-30까지)
  • 반복 일정 단일 수정
    • 반복일정을 수정하면 단일 일정으로 변경됩니다.
    • 반복일정 아이콘도 사라집니다.
  • 반복 일정 단일 삭제
    • 반복일정을 삭제하면 해당 일정만 삭제합니다.

선택

  • 반복 간격 설정
    • 각 반복 유형에 대해 간격을 설정할 수 있다.
    • 예: 2일마다, 3주마다, 2개월마다 등
  • 예외 날짜 처리:
    • 반복 일정 중 특정 날짜를 제외할 수 있다.
    • 반복 일정 중 특정 날짜의 일정을 수정할 수 있다.
  • 요일 지정 (주간 반복의 경우):
    • 주간 반복 시 특정 요일을 선택할 수 있다.
  • 월간 반복 옵션:
    • 매월 특정 날짜에 반복되도록 설정할 수 있다.
    • 매월 특정 순서의 요일에 반복되도록 설정할 수 있다.
  • 반복 일정 전체 수정 및 삭제
    • 반복 일정의 모든 일정을 수정할 수 있다.
    • 반복 일정의 모든 일정을 삭제할 수 있다.

심화 과제

  • 이 앱에 적합한 테스트 전략을 만들었나요?

각 팀원들의 테스트 전략은?


페어로 3인 1조로 작성했습니다. :1팀 이의찬, 1팀 김휘린, 5팀 양성진


이의찬

- 트로피가 답이다!!!
    1. 과제의 환경자체가 새로운 반복 일정 기능이 추가되는 등 요구사항이 계속 변경되는 환경이기에, E2E나 시각적 회귀 테스트를 작성하는 것은 비효율적일 것.
    2. 과제가 아니고 실제로 개발 환경일 경우, 당장 기능이 정상적으로 동작하는 것이 우선인데, 유닛 테스트를 우선적으로 작성하는 것 또한 비효율적일 것.
    
    ⇒ 그렇기에 통합테스트로 우선 요구사항이 적절하게 동작하는지부터 확인해야한다!
    

김휘린

- 단위 테스트를 세밀하게 늘리기보다는, 실제 사용자 시나리오에 가까운 흐름을 검증하는 것이 서비스 신뢰성을 높이는 데 더 효과적이다.
- 현재 통합 테스트는 범위상 E2E 테스트와 큰 차이가 없어 보인다.
- 다만 E2E 테스트는 실제 브라우저 환경과 실제 API를 대상으로 수행하기 때문에, 비슷해 보이더라도 반드시 별도로 수행할 필요가 있다.

양성진

- 통합테스트를 기본과제할때, 추가로 엣지케이스를 리스트업 해보면서 통합테스트를 조금 많이 작성해봤는데요, 
- 결국 통합테스트를 진행하면서 하는 유저의 사용여정이 e2e와 크게 다를게 없다고 생각해서  e2e를 할 필요없이 통합테스트만으로도 충분하지 않을까 싶었습니다.

합의된 테스트 전략과 그 이유는 무엇인가요?

현재 프로젝트 상황을 고려하여 테스트 트로피 전략에서 E2E 테스트를 제외하고 진행하는 것이 적절하다고 판단됩니다. 다음과 같은 근거들을 바탕으로 결정했습니다.

개발 단계 특성상의 고려사항

현재 개발 중인 프로덕트로서 요구사항과 기능 명세가 지속적으로 변경될 가능성이 높습니다. 이런 환경에서 E2E 테스트는 변경사항에 대한 유지보수 비용이 과도하게 높아질 수 있어 투자 대비 효율성이 떨어집니다.

테스트 시나리오의 중복성 문제

애플리케이션의 복잡도 수준에서는 통합 테스트와 E2E 테스트가 검증하는 시나리오가 크게 다르지 않습니다. 동일한 테스트 케이스를 다른 레이어에서 중복으로 작성하는 것보다, 통합 테스트에 집중하여 테스트 코드 작성의 효율성을 높이는 것이 바람직합니다.

사용자 여정의 단순성

아직 프로덕트가 성숙 단계에 이르지 않아 복잡한 멀티 스텝 사용자 플로우나 크로스 피처 시나리오가 많지 않습니다. 현재로서는 개별 기능 단위의 검증만으로도 충분한 커버리지를 확보할 수 있습니다.

모킹 인프라의 성숙도

MSW를 통한 API 모킹이 잘 구축되어 있어, 통합 테스트 레벨에서도 실제 네트워크 의존성 없이 안정적인 테스트 환경을 제공할 수 있습니다. 이는 E2E 테스트의 주요 장점 중 하나인 실제 환경 시뮬레이션의 필요성을 크게 줄여줍니다.

외부 의존성의 단순함

현재 외부 시스템과의 연동 포인트가 복잡하지 않아, 통합 테스트 레벨에서의 모킹으로도 충분히 엣지 케이스들을 커버할 수 있습니다. 따라서 실제 브라우저 환경에서의 E2E 검증이 추가로 제공하는 가치가 제한적입니다.

결론

이러한 상황에서는 효율성을 고려하여 정적 분석 도구와 통합 테스트에 집중하면서, 향후 프로덕트가 성숙해지고 복잡한 사용자 여정이 등장할 때 E2E 테스트 도입을 재검토하는 것이 현실적인 접근법이라고 생각합니다.

추가로 작성된 테스트 코드는 어떤 것들이 있나요?

  1. 반복 일정이면 캘린더와 리스트에 반복 아이콘이 표시된다
  2. 0분 일정(시작시간과 종료시간이 같음)을 저장할 수 없다
  3. 하루 종일 일정(00:00-23:59)을 저장하고 표시할 수 있다

시간 극값 테스트에 대한 의문

시간 극값 테스트 같은 경우는 솔직히 실제 사용자가 언제 저런 상황을 만날까? 싶긴 해요. 00:00부터 23:59까지 하루종일 일정을 잡는다거나, 시작시간과 끝시간을 똑같이 설정하는 경우가 얼마나 현실적인가 하는 생각이 들었습니다. 다만 이런 극값 테스트를 하는 이유는 시스템의 견고함을 확인하는 거예요. 개발자 입장에서는 이상한 값이 들어왔을 때 문제가 생기지 않을까?하는 관점에서 작성하는 해봤습니다.

충돌 경고와 시작/종료시간 검증

반면에 충돌 경고 후 계속 진행하는 케이스나 시작시간과 종료시간이 같을 때 에러가 나는 케이스는 사용자 관점에서 더 의미있다고 생각했습니다. 일정을 입력할 때 실수할 수 있는 상황들이 있다고 생각해봤고, 일정이 겹쳤을 때 "그래도 저장하고 싶다"는 사용자의 의도도 충분히 있을 수 있고요. 이런 케이스들이 사용자의 실제 행동과 더 가깝다고 느꼈습니다.

사용자 중심 테스트의 가치

결국 테스트도 사용자가 실제로 겪을 법한 상황을 기준으로 우선순위를 정하는 게 맞는 것 같습니다. 기술적으로 가능한 모든 경우의 수를 테스트하는 것보다는, 사용자가 "아, 이런 상황에서 앱이 이렇게 동작해주니까 편하네"라고 느낄 수 있는 시나리오들을 먼저 검증하는 게 더 의미있습니다. 그런 관점에서 보면 충돌 상황 처리나 잘못된 입력에 대한 적절한 안내 같은 건 정말 중요한 테스트 케이스고, 극값 테스트 같은 건 우선순위에서 밀려도 괜찮을 것 같습니다.


과제 셀프회고

기술적 성장

TDD

TDD 기본 개념

TDD는 테스트를 먼저 작성하고, 그 테스트를 통과하는 코드를 나중에 구현하는 개발 방법론입니다.

TDD 사이클 (Red-Green-Refactor)

it('사용자가 일정을 추가하면 목록에 표시된다', () => {
  // 아직 기능이 없으니 당연히 실패
  expect(screen.getByText('새 일정')).toBeInTheDocument();
});

// 2. Green: 테스트를 통과하는 최소한의 코드 작성
function addEvent() {
  return "새 일정"; // 일단 테스트만 통과시키기
}

// 3. Refactor: 코드 개선
function addEvent(eventData) {
  // 실제 비즈니스 로직 구현
  return processEvent(eventData);
}

처음 TDD를 접했을 때

TDD라는 걸 발제때 처음 들었을때, 이해가 안되고 어렵게만 느껴졌습니다.

과제를 해보면서

TDD 개념 이해 부족으로 기능을 먼저 구현한 후 테스트 코드를 작성했는데, 테스트 실패와 코드 수정을 반복하며 상당한 시간을 소모했습니다. 이 경험을 통해 테스트 코드가 요구사항의 명세서 역할을 한다는 것을 체감했습니다. 테스트를 통해 "이 기능은 어떻게 동작해야 하는가"가 명확히 정의되고, 개발자는 이 명세에 맞춰 코드를 구현하게 됩니다. 요구사항에 대한 모호함이 제거되고 명확한 기준이 생기기 때문에 개발 과정에서 안정감을 느낄 수 있었습니다. 테스트 통과 여부로 요구사항 충족 여부를 즉시 판단할 수 있죠. 다만 테스트 먼저 작성하는 과정이 단순 기능 구현보다 시간이 더 소요되는 비용 증가도 있었습니다.

코치님 말씀하신 리팩토링에서의 TDD 활용도 이해됩니다. 테스트가 기존 요구사항을 보장하는 안전장치 역할을 해서, 코드 구조 개선 중에도 기능 무결성을 유지할 수 있다는 의미였던 것 같습니다

지금 생각

아직 TDD를 완전히 잘한다고는 못하겠지만, 언제 쓰면 좋은지는 조금 감이 잡히는 것 같습니다. 복잡한 비즈니스 로직이나 자주 바뀔 것 같은 핵심 기능에는 TDD가 도움이 된다고 생각했습니다. 우선은 완벽하게 하려고 하지 말고, 필요한 곳에 조금씩 적용해보면서 경험을 쌓는 게 중요한 것 같습니다.

새롭게 다시 만들어 볼때, TDD의 프로세스를 토대로 한번 만들어 봐야겠다.

Vitest-preview 활용

스크린샷 2025-08-28 오후 1 31 36
  it('0분 일정(시작시간과 종료시간이 같음)을 저장할 수 없다.', async () => {
    setupMockHandlerCreation();

    const { user } = setup(<App />);

    await screen.findByText('일정 로딩 완료!');

    const checkBox = screen.getByLabelText('반복 일정');
    await user.click(checkBox); // 반복 해제

    await saveSchedule(user, {
      title: '순간 체크인',
      date: '2025-10-15',
      startTime: '14:30',
      endTime: '14:30',
      description: '빠른 상태 체크',
      location: '온라인',
      category: '업무',
    });

    await screen.findByText('시간 설정을 확인해주세요.');

    debug()
//.... 코드
);
  });

스냅샷마냥 디버깅을 심어놓은 구간에서 디버그를 돌리면 그 시점의 ui를 파악하고, 확인하면서 어디가 잘못됐는지 뭐가 이시점에서 어떤점이 문제였던걸까 이런건 눈으로 확인할수 있으니까 되게 편하고 좋았습니다. UI관련한 테스트를 할떄 눈으로 파악한다는점이 너무 좋았습니다.

과제 피드백

일단 여러모로 생각을 하면서 정답이 없는 상태서 만들다보니까 뜬 구름을 잡는거 마냥 조금 답답했습니다. 하지만 테스트 코드를 또 만들어보면서 TDD에대한 흐름과 생각이 조금은 잡아갈수 있는 챕터였던거 같습니다.

리뷰 받고 싶은 내용

    // ✅ 알림도 정상적으로 설정되는지 확인 (시간이 특별해도 알림 작동)
    act(() => {
      vi.advanceTimersByTime(24 * 60 * 60 * 1000 - 10 * 1000 * 60 - 1000);
    });
  1. vitest-preview로 확인해보고 알람이 두번씩 나와서 -1초를 하니까 2번 나오던게 한번 나오더라고요. 2번이 나오면 Found multiple elements with the text 이라고 나오더라고요. 그래서 저런식으로 알림작동을 하게 해서 한번만 나오게 하니까 테스트가 통과가 됐는데. 솔직히 만들면서 너무 억측스럽게 만들었다.? 이런 느낌이였습니다. 혹시 이런 방향으로 작성을 하는게 맞을까요?

과제 피드백

수고했습니다. 이번 과제는 TDD 방법론을 실제로 경험해보면서 테스트 주도 개발의 Red-Green-Refactor 사이클을 체험하는데 목적이 있었습니다. 지난 주 과제를 제대로 진행하지 못해서 이번 주에 테스트 코드와 TDD를 모두 학습하게 되었다고 하셨는데, 오히려 그 덕분에 더 깊이 있는 경험을 쌓으신 것 같네요.

Testing Library 쿼리 우선순위를 체계화한 접근이 인상적입니다. "getByRole + 정규식 → getElementById → getByLabelText" 순서로 정리하고, 각각의 장단점을 실제 MUI 환경에서 경험해보신 점이 좋았어요. 특히 "실제 사용자가 스크린 리더로 접근하는 방식과 동일해서 가장 안정적"이라는 관점은 정확합니다. 접근성을 고려한 테스트가 결국 더 좋은 사용자 경험으로 이어진다는 깨달음도 의미 있었고요.

"요구사항만 명확히 정리되어 있다면 이를 기반으로 테스트를 작성해달라고 요청하면 되니까 테스트를 작성하는 건 AI의 도움을 받기가 상대적으로 쉽다" 맞아요. AI에게 명확한 지시와 환각으로 인한 실수를 방지하기 위해서 TDD가 아주 강력한 방법으로 제시되고 있죠. 그래서 예전에는 비용은 들지만 하면 좋은 방법론이었다면 비용이 AI가 해줘서 줄어든다면 안할 이유가 없는 중요한 가치가 되어간다고 생각해요.

통합 테스트 위주로 접근한 전략도 납득됩니다. "프론트엔드는 기능 바꿔주세요라고 하면 화면에서 바로 그 변화가 보여야 하는데, 그런 사용자 경험은 통합 테스트 단계에서 명시된다"는 관점이 프론트엔드의 특성을 잘 이해한 접근이에요.

"테스트하기 쉬운 코드가 실제로 사용하기도 쉬운 코드"라는 체감을 하신 점도 좋네요. 클린코드와 챕터에서 항상 하던 말이었는데 테스트 챕터에서 확인을 했다니 너무 좋네요.

TDD는 그 방법뿐만 아니라 테스트 코드라는 것을 통해서 요구사항을 어떻게 컴퓨터가 더 쉽게 이해할 수 있도록 풀어내야하는가에 대한 생각을 키워주기에 멘탈모델로도 충분히 가치가 있으니 현업에서 어떻게 잘 접목해야할지를 생각해보기 바래요.

수고하셨습니다. 다음 과제도 화이팅입니다!

OFF: 안녕하세요! 오프입니다. 제가 결과를 수정했는데요. 심화과제를 불합격 시킨 이유는 전에 공지에 공유드렸듯이 e2e, 시각적 회귀테스트가 없다는 맥락이였습니다. 아쉽지만 참고 부탁드립니다ㅠㅠ