7주차 과제는 테스트 코드 작성입니다! 일정 관리 앱에 대한 테스트 코드를 작성하는 과제였는데, 처음 테스트 코드를 접하는 저에게는 정말 힘든 과제였습니다. 테스트 코드를 처음 써보는 입장에서 정말 많은 시행착오가 있었습니다. 공식 문서를 읽으면서 하나하나 테스트 코드...
드디어 항해 마지막 주차인 10주차가 되었습니다. 시간이 너무 빠른 것 같아요. 이제 수료만 남겨두고 있는 상황인데, 마지막인 만큼 10주차 과제에 대한 회고 내용을 열심히 정리해보겠습니다.
8주차 과제는 지난 과제에 이어서 추가 요구사항인 반복 일정 기능을 TDD(테스트 주도 개발) 방식으로 구현하는 것입니다. 이번 과제의 핵심은 7주차와 완전히 반대되는 접근인 거 같아요. 7주차는 기존 코드에 테스트를 추가하는 방식이었다면, 8주차는 테스트를 먼저 작성...
8주차 과제는 지난 과제에 이어서 추가 요구사항인 반복 일정 기능을 TDD(테스트 주도 개발) 방식으로 구현하는 것입니다. 이번 과제의 핵심은 7주차와 완전히 반대되는 접근인 거 같아요. 7주차는 기존 코드에 테스트를 추가하는 방식이었다면, 8주차는 테스트를 먼저 작성...
이전 블로그 링크: https://velog.io/@chan9yu/hanghae-plus-wil7

(모르겠어... 테스트 코드 하나도 모르겠어..!!)
Chapter 3 테스트 코드의 7주차가 시작되었습니다. 지난주 연차의 여유로움은 끝나고 다시 일상으로 돌아왔지만, 그래도 이번 주는 적당히 바쁘지 않아서 과제에 집중할 수 있었어요.

하지만... 목요일 또 날밤을 새버리고..

출근해버렸따... ㅇ<-<

그냥 포기하고 목요일은 밤새는 날로 하자...
7주차 과제는 테스트 코드 작성입니다!
이번 과제는 난이도를 선택할 수 있었는데
저는 Medium 난이도를 선택했습니다. 테스트 코드를 제대로 써본 적이 없어서 설정부터 다 직접 하기엔 무리라고 판단했거든요... (사실 Hard 찍먹하다가 배탈 나서 Medium으로 도망갔습니다 ㅠㅠ)

과제 목표: 총 11개 파일, 115개의 단위 테스트를 작성하고 통과시키기
일정 관리 앱에 대한 테스트 코드를 작성하는 과제였는데, 처음 테스트 코드를 접하는 저에게는 정말 힘든 과제였습니다.
테스트 코드를 처음 써보는 입장에서 정말 많은 시행착오가 있었습니다. 공식 문서를 읽으면서 하나하나 테스트 코드를 작성해나갔습니다.
처음 접한 React Testing Library의 핵심 개념들을 배우는 것부터 시작했습니다
// 예시: 다양한 selector 활용법
const titleInput = screen.getByLabelText("제목");
const submitButton = screen.getByRole("button", { name: "일정 추가" });
const errorMessage = screen.queryByText("필수 필드를 입력해주세요");
const successToast = await screen.findByText("일정이 추가되었습니다"); 서버 요청을 가로채서 테스트하는 MSW (Mock Service Worker) 사용법도 배웠습니다
export const setupMockHandlerCreation = (initEvents = [] as Event[]) => {
const mockEvents: Event[] = [...initEvents];
server.use(
http.get("/api/events", () => {
return HttpResponse.json({ events: mockEvents });
}),
http.post("/api/events", async ({ request }) => {
const newEvent = (await request.json()) as Event;
newEvent.id = String(mockEvents.length + 1);
mockEvents.push(newEvent);
return HttpResponse.json(newEvent, { status: 201 });
})
);
}; 각 테스트마다 독립적인 환경을 만들어 병렬 실행 시에도 안정적인 테스트가 가능하게 했습니다.
테스트가 실행 시점에 따라 다른 결과를 내는 것을 방지하기 위해 고정된 시간을 설정했습니다
beforeEach(() => {
expect.hasAssertions(); // 모든 테스트가 assertion을 가지도록 강제
vi.setSystemTime(new Date("2025-10-01")); // 고정 시간 설정
resetEvents();
}); vi.setSystemTime()을 사용하면 시간에 의존하는 코드(new Date(), 날짜 계산 로직 등)를 일관되게 테스트할 수 있어요. 실행 시점마다 결과가 달라지는 것을 막아줍니다!
expect.hasAssertions()도 중요한 설정 중 하나였습니다
test("콜백이 실제로 호출되는지 확인", () => {
expect.hasAssertions(); // 반드시 expect가 실행되어야 함
onEventCreate((data) => {
expect(data).toBeTruthy(); // 이 검증이 실행되지 않으면 테스트 실패
});
// 콜백이 호출되지 않으면 테스트 실패
}); 조건문이나 비동기 코드 때문에 검증문(expect)이 실행되지 않아도 테스트가 통과하는 "빈 껍데기 테스트" 문제를 방지해줍니다.
테스트 작성과 함께 거대한 App 컴포넌트를 적절한 단위로 분리하는 작업도 진행했습니다
테스트가 깨지지 않는 선에서 조금씩 컴포넌트를 분리해나가는 게 핵심이었어요.

목표했던 총 115개의 테스트를 모두 통과시킬 수 있었습니다!
목요일 밤을 새워가며 마지막까지 테스트를 완성했는데, 정말 다행이네요 ㅠㅠ
그동안 기능이 잘 돌아가는지만 보던 것에서 벗어나서, 실제로 사용자가 쓰는 관점에서 컴포넌트가 제대로 동작하는지 확인하는 방법을 배웠습니다.
특히 "컴포넌트가 렌더링되는가" 같은 기본 테스트부터 복잡한 사용자 시나리오까지 다양하게 작성해보면서 테스트의 범위와 깊이에 대해 고민할 수 있었습니다.
아직 어떤 테스트를 작성해야 하는지, 어느 정도 선에서 테스트를 작성하는 게 적절한지 감을 잘 잡지 못했습니다.
"컴포넌트가 렌더링되는가" 같은 기본적인 테스트가 실제로 의미가 있는 건지, 아니면 좀 더 비즈니스 로직에 집중해야 하는 건지 고민이 많았던 것 같습니다.
단순히 테스트 개수를 늘리는 것보다는 진짜 중요한 비즈니스 로직에 집중하는 테스트를 작성하고 싶습니다.
복잡한 상태 관리가 있는 컴포넌트를 어떻게 테스트할지, E2E 테스트와 단위 테스트를 어떤 비율로 써야 할지도 더 공부해보고 싶습니다.
이번에는 기존 코드에 테스트를 추가하는 방식이었는데, 다음에는 테스트를 먼저 작성하고 기능을 구현하는 TDD 방식을 시도해보고 싶습니다. (마침 다음 주차 과제가 TDD라서 해볼 수 있을 것 같네요!)
실제 업무에서 테스트 코드를 어떻게 도입하고 활용할지에 대한 전략을 세워보고 싶습니다. 팀원들과 함께 테스트 코드에 대해 공유하고, 점진적으로 도입하는 방법을 고민해보려고 합니다.
이번 7주차는 테스트 코드라는 생소한 영역에 발을 들여놓으면서 많은 어려움도 있었지만, 그만큼 얻어간 점도 많은 것 같습니다.
단순히 기능이 돌아가는지 확인하는 것을 넘어서서, 실제 사용자가 어떻게 상호작용하는지를 고려하면서 코드를 작성했던 부분이 재미있었습니다.
어렵겠지만 앞으로 실무에서도 기회가 되면 테스트 코드를 적극 활용해서 더 안정적이고 품질 높은 코드를 작성하고 싶은 마음이 생긴 것 같습니다.

싸이버렉카 둘...

(ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ)