난이도에 맞는 템플릿을 선택해서 작성해주세요!
7주차 과제 체크포인트
기본 과제
HARD
7주차 과제 체크포인트
기본과제
- 총 11개의 파일, 115개의 단위 테스트를 무사히 작성하고 통과시킨다.
질문
Q. handlersUtils에 남긴 질문에 답변해주세요.
handlers만 사용했을 때 2가지의 문제가 발생합니다.
- 테스트 간 데이터 오염 현상
- 병렬 동작 시 같은 배열을 수정하므로 매번 같은 결과가 아닌 예측 불가능한 결과를 발생시킴
export const setupMockHandlerCreation = (initEvents = [] as Event[]) => {
const mockEvents = [...initEvents];
server.use(
http.get('/api/events', () => {
return HttpResponse.json({ events: mockEvents });
}),
http.post<PathParams, EventForm>('/api/events', async ({ request }) => {
const newEvent = await request.json();
const id = `${mockEvents.length + 1}`;
mockEvents.push({ ...newEvent, id });
return HttpResponse.json({ ...newEvent, id });
})
);
};
// setupTests.ts
afterEach(() => {
server.resetHandlers();
vi.resetAllMocks();
});
// 테스트 1
test('create event', () => {
setupMockHandlerCreation([]); // mockEvents = [] 생성
});
// afterEach에서 핸들러만 제거, mockEvents는 [event1] 상태로 메모리에 남음
// 테스트 2
test('another test', () => {
setupMockHandlerCreation([]); // 새로운 mockEvents = [] 생성
// 핸들러는 오버라이딩, 새로운 배열 전달로 인해 깨끗한 상태에서 시작 ✅
});
2가지의 문제를 해결하기 위해 유틸 함수의 인자로 mockEvents를 받아 얕은복사를 진행해 사용하게 했습니다. 그리고 server.use 를 통해 server에 적용된 http 핸들러 내용을 오버라이드 해서 독립적인 환경을 만들었습니다. 각 테스트가 끝나고 handlers 자체도 리셋되기에 안전한 환경이라고 생각합니다.
Q. 테스트를 독립적으로 구동시키기 위해 작성했던 설정들을 소개해주세요.
// 1. 함수 스코프를 이용해 mockEvents 데이터 생성
export const setupMockHandlerCreation = (initEvents = [] as Event[]) => {
const mockEvents = [...initEvents]; // 각 호출마다 독립적인 배열 생성
// ...
};
// 2. 테스트 시작 전 시간 정보 동일하게 설정
beforeEach(() => {
vi.setSystemTime(new Date('2025-10-01')); // 모든 테스트가 동일한 기준 시간
});
// 3. 개별 테스트가 끝난 후 Mocks 정보와 Handlers 초기화
afterEach(() => {
server.resetHandlers();
vi.resetAllMocks();
});
// 4. 독립 환경 테스트가 필요한 부분에서 유틸 함수 사용
test('이벤트 생성', () => {
setupMockHandlerCreation([]); // 이 테스트만의 독립적인 mockEvents, Handlers 생성
// ...
});
심화 과제
- App 컴포넌트 적절한 단위의 컴포넌트, 훅, 유틸 함수로 분리했는가?
- 해당 모듈들에 대한 적절한 테스트를 5개 이상 작성했는가?
과제 셀프회고
후기
테스트코드를 처음으로 작성해보면서 느낀건 코드를 잘 작성해둬야 테스트가 편하다는 말이 무엇인지 체감됐습니다 컴포넌트에 aria-label, role 설정 등 각 의미에 맞는 시멘틱한 태그사용과 접근성을 고려하면 테스트 코드를 작성할 때 자연스럽게 사용할 수 있는 요소들이 많아지는 것 같습니다.
테스트코드를 작성해본 경험이 없음에도 오기로 Hard 난이도를 선택해서 처음엔 setupTests와 handlersUtils는 건드리지도 못했지만.. Unit 테스트부터 차근차근 해결해 나갔더니 medium에서 어떤걸 사용해야할지는 여전히 몰랐지만 어떠한 "설정"이 필요한지가 느껴져 이런 기능이 되나? 저런 기능도 지원해주나? 하면서 어찌저찌 풀어간 것 같습니다ㅎㅎ..
아직도 테스트코드를 작성하는 기준 자체는 모호함이 느껴지지만 다양한 메서드들을 찾아보며 테스트 코드를 읽어나가는 건 확실히 가능할 것 같습니다!
아쉬운 부분
- 각 테스트 케이스의 필요성 유무에 대해 명확한 판단 기준이 세워지지 않았습니다. (컴포넌트 테스트일 경우 ~~이건 해야한다, 통합 테스트일 경우 ~~이건 해야한다)
- 과제 각 테스트 케이스의 설명에 대해 깊게 고민해보지 못한 것 같습니다.
- 리팩토링 시 Props 개선이나 순수함수, 혹은 관심사 별 훅 분리를 진행하지 못했습니다 (현재 시각 07:02분,,,,)
성장한 부분
- 테스트코드를 읽고, 잘못된 부분을 찾아낼 수 있습니다.
- GetBy~ FindBy~ 의 차이점을 명확히 알았습니다. (동기 비동기)
- 테스트 환경에서 동일한 환경설정에 대한 중요성을 알았습니다.
- 테스트를 고려한 코드를 짜야하는 이유에 대해 깨달았습니다.
리뷰 받고 싶은 내용
-
setupTests쪽에서
vi.useFakeTimers({ shouldAdvanceTime: true });을 설정했습니다. 해당 옵션은 제가 이해하기로는 테스트속에서 시간이 흐르도록 만드는 옵션으로 이해했습니다. 그치만 medium.useNotifications.spec 테스트 코드 작성 시 vi.advanceTimersByTimeAsync(1000), 혹은 waitFor(()=>,{timeout:2000}) 형태의 코드를 넣어주지 않으면 시간이 흐른걸 테스트 하기가 어려웠습니다 해당 두 메서드 사용이 괜찮을까요? 더 좋은 방법이 있었을까요? -
컴포넌트 테스트 코드 작성 시 어떤걸 작성해야할지 조금 어렵습니다. 예를 들어 EventFormPanel 컴포넌트에 대한 테스트 작성 시 일정 수정, 일정 추가는 통합테스트에서 진행하는데 그럼 이 폼은 어떤걸 테스트해야하는걸까하는 생각이 들었습니다.
-
퍼블리싱을 할 때 각 역할에 맞는 role, aria-label 같은 요소들을 모두 설정해주는게 좋을까요? 어떤 UI는 없고 어떤 UI는 있는 경우들이 있는데 설정하는 기준이 궁금합니다!
과제 피드백
수고하셨습니다 윤우님!
Q. setupTests쪽에서 vi.useFakeTimers({ shouldAdvanceTime: true });을 설정했습니다. 해당 옵션은 제가 이해하기로는 테스트속에서 시간이 흐르도록 만드는 옵션으로 이해했습니다. 그치만 medium.useNotifications.spec 테스트 코드 작성 시 vi.advanceTimersByTimeAsync(1000), 혹은 waitFor(()=>,{timeout:2000}) 형태의 코드를 넣어주지 않으면 시간이 흐른걸 테스트 하기가 어려웠습니다 해당 두 메서드 사용이 괜찮을까요? 더 좋은 방법이 있었을까요?
A. 제가 예전에 정리한건 shouldAdvanceTime만은 타이머를 한번에 꽝하고 시간을 조절하는 것이 아니라 조금씩 흐르는 것을 시뮬레이션만 해줄뿐 온전하게 시간이 흐르고 타이머의 콜백들이 온전하게 실행되게 하려면 시간을 쭈욱 밀어주는 작업이 필요하다로 정리했어요. 그게 vi.advanceTimersByTimeAsync()죠. 즉 shouldAdvanceTime 설정은 그냥 타이며 시간이 흐름에 관한 이야기고 온전히 시간히 흐른것을 보장해 모든 콜백을 실행하는 것은 별개의 이야기 인것이죠.
Q. 컴포넌트 테스트 코드 작성 시 어떤걸 작성해야할지 조금 어렵습니다. 예를 들어 EventFormPanel 컴포넌트에 대한 테스트 작성 시 일정 수정, 일정 추가는 통합테스트에서 진행하는데 그럼 이 폼은 어떤걸 테스트해야하는걸까하는 생각이 들었습니다.
A. 그러니까 중복테스트에 대한 이야기죠? 이건은 테스트전략을 짜기 나름인 것 같아요. 예를들어 단위테스트에서는 EventFormPanel의 스펙을 테스트하고, 통합테스트에서는 EventFormPanel를 사용하는 좀 더 큰 컴포넌트 예를들면 page레이어에서 통합테스트를 진행할수도 있는 것이지요. 저라면 그렇게 전략을 짤것 같아요~
Q. 퍼블리싱을 할 때 각 역할에 맞는 role, aria-label 같은 요소들을 모두 설정해주는게 좋을까요? 어떤 UI는 없고 어떤 UI는 있는 경우들이 있는데 설정하는 기준이 궁금합니다!
A. 어떤것이 더 옳은가 혹은 나은가에 대한 이야기라면 최대한 많이 aria를 커버하는 것이 접근성에는 좋을 수밖에 없어요. 하지만 실무에서는 많이 못챙기는데요 ㅎㅎㅎ 오히려 테스트를 작성할때 후킹(엘리먼트 찾기)용도로는 좋은 추상이라고 생각해서 테스트를 위해 자주 사용합니다 저는 ㅎㅎ