인프런 커뮤니티 질문&답변

박일상님의 프로필 이미지
박일상

작성한 질문수

실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트

3.4. 타이머 테스트

debounce 함수 테스트 정확도 관련 질문입니다.

작성

·

19

0

안녕하세요. debounce 함수 테스트 관련 강의를 보고 궁금한 점이 있어 문의드립니다.

 

debouncedFn이 300ms이 지난 후 실행되어야 함을 테스트할 때, 기존에 작성해주신 것 처럼 테스트할 시에는 함수가 300ms 후가 아닌 즉시 실행이 되거나 그보다 작은 시간이 지나고 실행이 되어도 테스트가 통과하게 됩니다.

 

그에 따라 아래처럼 작성하는 것이 더 정확한 테스트라고 생각이 되는데 이렇게 테스트하지 않는 이유가 있는지 궁금합니다!

 

  it('특정 시간이 지난 후 함수가 호출된다.', () => {
    const spy = vi.fn();

    const debouncedFn = debounce(spy, 300);

    debouncedFn();
    expect(spy).not.toHaveBeenCalled(); // 즉시 호출되지 않았는지 확인

    vi.advanceTimersByTime(299);
    expect(spy).not.toHaveBeenCalled(); // 299ms 후에도 호출되지 않았는지 확인

    vi.advanceTimersByTime(1);
    expect(spy).toHaveBeenCalledTimes(1); // 300ms 후에 정확히 한 번 호출되었는지 확인

    expect(spy).toHaveBeenCalled();
  });

답변 2

0

코드 조커, 오프님의 프로필 이미지
코드 조커, 오프
지식공유자

안녕하세요 일상님!

debouncedFn이 300ms이 지난 후 실행되어야 함을 테스트할 때, 기존에 작성해주신 것 처럼 테스트할 시에는 함수가 300ms 후가 아닌 즉시 실행이 되거나 그보다 작은 시간이 지나고 실행이 되어도 테스트가 통과하게 됩니다.

이 말씀에 대해 조금 더 여쭤보고 싶은데요! 혹시 이런 경우에 작은 시간이 지나도 테스트가 성공한다는 의미는 어떤건지 알 수 있을까요? 제가 추측해보면

it('특정 시간이 지난 후 함수가 호출된다.', () => {
  const spy = vi.fn();

  const debouncedFn = debounce(spy, 300);

  debouncedFn();

  expect(spy).toHaveBeenCalled(); // 추가

  vi.advanceTimersByTime(300);

  expect(spy).toHaveBeenCalled();
});

이렇게 했을 때 통과되는 것 아니냐 라는 의미로 이해했는데 괜찮을까요? 제가 테스트를 했을 때는 해당 시나리오에 대해서는 통과하지 않아서 조금 더 설명해주시면 저희가 작성한 코드가 잘못된 부분이 있는지 확인을 해보도록 하겠습니다.

 

추가로 말씀해주신대로 좀 더 구체적으로 호출이 되지 않았음을 확인한 뒤 이후에 호출이 되었음을 확인하고 싶다면, 작성해주신 코드에서 조금만 수정해서

  it('특정 시간이 지난 후 함수가 호출된다.', () => {
    const spy = vi.fn();

    const debouncedFn = debounce(spy, 300);

    debouncedFn();
    expect(spy).not.toHaveBeenCalled(); // 즉시 호출되지 않았는지 확인

    vi.advanceTimersByTime(300);
    expect(spy).toHaveBeenCalledTimes(1); // 300ms 후에 정확히 한 번 호출되었는지 확인
  });

정도로만 검증을 해도 충분하지 않을까 싶습니다! 만약 경계에 대한 명확한 트리거 시점에 대해 검증을 하고 싶으시다면 작성해주신대로 (마지막 toHaveBeenCalled만 제거하고) 작성해주셔도 충분히 좋은 검증 방식이신 것 같습니다.

추가로 궁금한 점 있으시면 편하게 질문주세요~ 감사합니다!

박일상님의 프로필 이미지
박일상
질문자

안녕하세요! 빠른 답변 감사합니다. 조금 더 구체적으로 말씀드리겠습니다!
기존의 코드로 테스트할 경우 debounce의 구현이 잘못되어 입력 받은 초보다 빨리 실행을 하도록 구현이 되어있어도 해당 테스트를 통과하기 때문에 정확한 테스트가 아니라고 생각했습니다. 예를 들어, debounce 함수가 잘못 구현되어 입력값에 관계 없이 200ms만 지나도 실행이 되도록 구현이 되어있더라도 테스트를 통과하게 된다는 의미였습니다. 그래서 299ms가 지났을 때까지는 실행이 안되고 300ms가 지났을 때는 실행되는 동작으로 테스트를 작성해서 질문 드렸습니다! (마지막 toHaveBeenCalled는 지워야했는데 실수로 안 지우고 붙여넣기를 한 것 같습니다.)

이런식으로 구체적으로 테스트 하지 않는 이유에 대해서 궁금하여 질문드렸습니다!

코드 조커, 오프님의 프로필 이미지
코드 조커, 오프
지식공유자

아~ 넵 이해했습니다. 아마..당시 특별한 이유는 없었던 것 같고, 당시에 해당 타이머 기능에 대해 설명을 드리는게 주여서 저렇게 했던 것 같은데요 ㅎㅎ 실제로 복잡한 구조의 코드는 아니니 저정도로 작성하지 않았나 싶습니다. 만약 꼼꼼하게 보고 싶다면 말씀해주신대로 테스트를 작성하시면 좀 더 보강이 될 수 있을것 같네요. 좋은 의견 감사합니다~

0

안녕하세요, 인프런 AI 인턴입니다. 박일상님.

debounce 함수의 정확한 작동을 테스트하기 위한 접근법에 대해 질문해 주셨네요. 말씀하신 것처럼, debouncedFn이 정확히 300ms 후에 호출되는지를 확인하는 테스트는 debounce 함수를 테스트할 때 중요한 부분입니다.

사실, debounce 함수의 시간 기반 로직을 검증할 때는 두 가지 주요 사항을 확인해야 합니다. 첫째, 함수가 지정한 시간 이전에 호출되지 않는 것, 둘째, 시간을 초과하였을 때 정확히 호출되는 것입니다. 박일상님이 제안하신 코드처럼 299ms와 300ms를 구분하여 각각 호출 여부를 확인하는 것은 정확성과 신뢰도를 높이는 데 매우 유용합니다.

기존 테스트가 덜 정확한 이유는, 일반적으로 특정 시간 이후 함수가 호출되는지만 확인을 하고 이전 시간에 호출되지 않음을 명시적으로 검증하지 않는 경우가 많기 때문입니다. 하지만 더 정밀한 테스트를 위해, 말씀하신 코드처럼 299ms에서 호출되지 않는지 검증하는 것이 바람직합니다.

관련된 내용을 좀 더 공부하시려면 다음 URL을 참고하실 수 있습니다:
타이머 함수 테스트 정확히 이해하기

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

박일상님의 프로필 이미지
박일상

작성한 질문수

질문하기