1. 문제 (과제, 프로젝트를 진행하면서 부딪혔던 기술적인 문제)
- 아래 테스트가 정상적으로 pass되었지만 화요일이 되니까 fail 되었다.
it('총액이 올바르게 계산되는지 확인', () => {
sel.value = 'p1';
addBtn.click();
addBtn.click();
expect(sum.textContent).toContain('총액: 20000원(포인트: 20)');
});
it('포인트가 올바르게 계산되는지 확인', () => {
sel.value = 'p2';
addBtn.click();
expect(document.getElementById('loyalty-points').textContent).toContain(
'(포인트: 128)',
);
});
✅ 원하는 결과
// 필요
총액: 20000원(포인트: 20)
❌ 실제 출력 (문제 발생)
// 실제
총액: 18000원(10.0% 할인 적용)(포인트: 18)
2. 시도
- 00시 이전부터 이후까지 과제를 하고 있었기에 작성 중인 로직에서 문제가 생긴 줄 알고 계속해서 수정했다.
- 디버깅하는 도중에 disCountRate가 계속해서 0.1(화요일 할인율)로 반영 되는 것을 발견하고 오늘이 화요일라는 것을 깨달았고 테스트 코드에서 문제가 있다는 것을 생각함
const calculateTotalAmount = () => {
let totalAmount = 0;
let cartItemCount = 0;
let subTotalAmount = 0;
const cartItems = [...elements.cartItemsContainer.children];
const products = state.products;
for (const item of cartItems) {
// 현재 상품 찾기
const currentProduct = products.find((product) => product.id === item.id);
// 수량 추출
const quantity = parseInt(
item.querySelector('span').textContent.split('x ')[1],
);
// 상품 가격 계산
const currentProductPrice = currentProduct.price * quantity;
let disCountRate = 0;
// 수량 증가
cartItemCount += quantity;
// 총 가격 계산
subTotalAmount += currentProductPrice;
// 할인 적용
if (quantity >= 10) {
disCountRate = PRODUCT_CONFIG.DISCOUNT_RATE[currentProduct.id] || 0;
}
// 할인 가격 계산
totalAmount += getDiscountPrice(currentProductPrice, disCountRate);
}
let discountRate = 0;
// 30개 이상 구매시 25% 할인
if (cartItemCount >= 30) {
const bulkDiscount = totalAmount * 0.25;
const itemDiscount = subTotalAmount - totalAmount;
// 총 할인 가격이 상품 할인 가격보다 크면 총 할인 가격 적용
if (bulkDiscount > itemDiscount) {
totalAmount = getDiscountPrice(subTotalAmount, 0.25);
discountRate = 0.25;
} else {
// 총 할인 가격이 상품 할인 가격보다 작으면 상품 할인 가격 적용
discountRate = (subTotalAmount - totalAmount) / subTotalAmount;
}
} else {
// 30개 미만 구매시 할인 가격 계산
discountRate = (subTotalAmount - totalAmount) / subTotalAmount;
}
// 화요일 할인 적용
const isTuesday = new Date().getDay() === 2;
if (isTuesday) {
totalAmount = getDiscountPrice(totalAmount, 0.1);
discountRate = Math.max(discountRate, 0.1);
}
return { totalAmount, discountRate, cartItemCount };
};
3. 해결
🛠 원인
- 날짜 의존성: 테스트가 실행되는 실제 날짜에 따라 테스트 결과가 달라짐
- 화요일이 되면 기존에 있던
textContext
를 확인하는 테스트가 화요일 할인 로직으로 인해 통과하지 않음
- 화요일이 되면 기존에 있던
- 모킹 범위 문제: 개별 테스트에서
vi.useFakeTimers()
를 호출하고vi.useRealTimers()
로 복원하지 않으면 다음 테스트에도 영향 - 일관성 부재: 실행 시점에 따라 테스트가 통과하기도, 실패하기도 함 (화요일에만 통과하지 않는 테스트들)
🔍 현재 코드의 문제점 및 해결 방법
🔍 1. 테스트 코드의 흐름
- 현재 테스트 코드에선 화요일에 대한 테스트 코드가 적혀있지만, 실행 날짜에 따라 테스트 결과가 달라지는 문제가 있다.
- 특정 테스트는 화요일 할인을 검증하지만, 다른 테스트에서는 요일 할인이 적용되면
fail
이 발생한다. - 화요일 할인 테스트에는 명시적으로 화요일 날짜를 설정해야 하지만, 다른 테스트에는 영향을 주지 않아야 한다.
✅ 2. 해결 방법
// beforeEach와 afterEach를 활용한 테스트 환경 관리
beforeEach(() => {
vi.useFakeTimers();
const mockDate = new Date('5831-12-15'); // 화요일이 아닌 다른 요일
vi.setSystemTime(mockDate);
vi.spyOn(window, 'alert').mockImplementation(() => {});
});
afterEach(() => {
vi.useRealTimers();
vi.restoreAllMocks();
});
- 가짜 타이머 사용:
vi.useFakeTimer()
로 모든 테스트에서 일관된 시간 환경 설정 한다.- 화요일이 되었을 때 기존 다른 테스트들이
fail
이 되기 때문에 다른 테스트들이 실행 되기 전(beforeEach()
)에 화요일이 아닌 다른 요일로 바꿔준다.
- 화요일이 되었을 때 기존 다른 테스트들이
- 고정 날짜 설정: 화요일이 아닌 다른 날짜(
5831-12-15
)로 모든 테스트 실행한다. - 시스템 시간 조작:
vi.setSystemTime(mockDate)
으로JavaScript
의 날짜/시간 함수 결과 통제. - 환경 복원: 각 테스트 후(
afterEach()
)vi.useRealTimers()
로 환경 정리.
✨ 결과
- 모든 테스트가 동일한 날짜 환경에서 실행되어 정상 적으로 테스트
pass
- 실제 실행 날짜와 관계없이 항상 같은 결과 생성한다.
4. 알게된 것
- 각 테스트는 독립적으로 실행되어야 한다.
vi.useFakeTimers()
와vi.setSystemTime()
을 활용한 시간 모킹 방법.beforeEach
와afterEach
로 환경 관리 방법.- 테스트 후
vi.useRealTimers()
와vi.restoreAllMocks()
을 통한 환경 복원.
Keep : 현재 만족하고 계속 유지할 부분
- 테스트 환경을 제어하는 `vi.useFakeTimers`와 `vi.setSystemTime`의 활용법을 익혀 날짜 의존적인 문제를 해결했다는 점에서 큰 성과가 있었다.
- 문제를 인지하고, 원인을 분석하며, 적합한 해결 방안을 적용하는 단계적인 접근 방식을 성공적으로 수행했다.
- `beforeEach`와 `afterEach`를 통해 테스트 환경을 독립적으로 유지하고, 다른 테스트에 영향을 미치지 않도록 설계한 점이 테스트 코드 주차에 유용할 것 같다.
Problem : 개선이 필요하다고 생각하는 문제점
- 문제를 해결하기 위한 방법을 적용했지만, 초기에 테스트 설계 시 날짜 의존성을 제거하지 못해 불필요한 디버깅 시간을 소모했다.
Try : 문제점을 해결하기 위해 시도해야 할 것
- 비즈니스 로직이 특정 환경(날짜, 시간 등)에 의존하지 않도록 설계하고, 이를 명확히 분리해 독립적으로 테스트할 수 있도록 개선해야 할 것 같다.
- 해결책을 적용하기 전 팀원들과의 코드 리뷰를 통해 다양한 의견과 접근 방식을 반영하도록 해야겠다.
'항해 플러스 > 회고' 카테고리의 다른 글
[항해 플러스 프론트엔드] 7주차 회고 - MSW(Mock Service Worker) (0) | 2025.05.23 |
---|---|
[항해 플러스 프론트엔드] 6주차 회고(챕터2 종료) - 튜닝의 끝은 순정이다 (4) | 2025.05.23 |
[항해 플러스 프론트엔드] 3주차 회고(챕터1 종료) - 아는 만큼 보인다 (2) | 2025.04.11 |
[항해 플러스 프론트엔드] 2주차 회고 - 모르는데 어떻게 해요 (2) | 2025.04.04 |
[항해 플러스 프론트엔드] 1주차 회고 - 살아 남기 (3) | 2025.03.28 |