자바스크립트 테스트 코드 작성


(류한경) #1

테스트 코드 작성하기

개인 프로젝트에서 자바스크립트에 대한 테스트 코드를 작성하고자 합니다.

프론트엔드 기술 스택은 아래와 동일합니다.

  • webpack
  • typescript
  • mocha, chai

테스트 환경을 구축하기 전에 만들어놓은 슬라이드 모듈이 있습니다. 이 모듈은 다음, 이전버튼을 누르면 미끄러지면서 이미지가 변경됩니다. 저는 해당 모듈을 시작으로 테스트 코드를 작성하고자 합니다. 테스트코드를 작성하기 위해 다양한 글을 읽고 예제를 따라하면서 대략적인 작성방법을 알게 되었습니다. 하지만 의문점이
있어서 질문드립니다.

SliderTemp.ts - 매우 간단한 슬라이드 예제

class SliderTemp {
    private slider: Element;
    private prev: Element;
    private next: Element;
    private li: HTMLLIElement[];
    private position: number = 0;

    constructor() {
        this.slider = document.querySelector(".slider")!;
        this.prev = this.slider.querySelector(".prev")!;
        this.next = this.slider.querySelector(".next")!;
        this.li = Array.from(this.slider.querySelectorAll("li"))!;
        this.clickEvent();
    }

    private clickEvent(): void {
        this.prev.addEventListener("click", (e: Event): void => {
            e.preventDefault();
            this.position -= 100;
            this.slide();
        });

        this.next.addEventListener("click", (e: Event): void => {
            e.preventDefault();
            this.position += 100;
            this.slide();
        });

    }

    private slide(): void {
        const length = this.li.length;

        if (this.position === length * 100) {
            this.position = 0;
        } else if (this.position === -100) {
            this.position = (length - 1) * 100;
        }

        this.li.forEach((value) => {
            value.style.transform = `translateX(-${this.position}%)`;
        });
    }
}

export default SliderTemp;

의문점

  • 테스트 코드에 DOM 테스트가 추가되어야합니까? SliderTemp.ts 파일을 살펴본다면 li의 갯수를 가져와서 연산에 사용하는 것을 알 수 있습니다. (이것은 강하게 결합되어있습니다.) 이런 경우 테스트 코드 작성시 반드시 DOM을 불러와야할 필요가 있습니다. 그래서 저는 이 경우에 의해서 jsdom을 사용할 것입니다.
    하지만, DOM 테스트를 작성하는 것에 대해 의문을 가지는 StackOverFlow 글을 보았습니다. 그들은 DOM 테스트를 작성할 필요가 없으며 테스트는 비지니스 로직을 중점적으로 작성해야한다고 합니다. 만약 그들의 주장이 맞다면 저는 View와 Logic을 분리하고 Logic에 관해서만 테스트를 작성하면 됩니까? 아니면 현재 소스코드 그대로 테스트를 작성해도 될까요? 이것에 정답은 없겠지만 실제 현업에서 일해본 경험이 없기에 선배 개발자분들의 이야기를 듣고 싶습니다.

    DOM 테스트 작성이 의미있는 행위인가요?


(이종은(Jong Lee)) #2

DOM 테스트 자체가 무의미한 것은 아닙니다. 어떤 글을 보셨는지 모르겠지만 보통 DOM을 다루는 방식이 DOM을 테스트하기 쉽지 않았었기 때문에 그럴겁니다. React와 같이 컴포넌트 기반일 props(입력)에 따라 경우 최종 렌더링 되는 DOM(출력)을 테스트하기 간편합니다. React의 이러한 테스트를 위해 페이스북이 만든 Jest라는 테스트 도구에는 snapshot 기능이 있습니다.

테스트 코드에 대한 저의 생각을 간단히 정리해 보자면 “테스트가 가능하다면 테스트 코드를 작성하는 것은 의미가 있다” 입니다.

여기서 테스트가 가능하다는 것은 테스트를 하는 대상이 예측이 가능하다는 얘기입니다. 함수를 예를 들자면 어떤 인자(입력)을 주면 어떤 리턴값(결과)가 나와야 정상이다라고 말할 수 있다면 그것은 예측 가능한 것이며 어떤 입력을 줬을 때 어떤 결과가 나와야하는지를 가지고 테스트 코드를 짤 수 있습니다. 하지만 이 함수의 결과가 입력에 따라서만 결과가 달라지는 것이 아니라 글로벌 변수와 같은 주변의 다른 것에 따라 결과가 달라지고 있다면 이 함수를 테스트 하기 위해서는 그 주변 환경을 실제 이 함수가 사용되는 환경을 흉내(Mock) 내도록 만들고 테스트를 해야겠죠. 만약 이런 Mock을 만들기 어렵다거나 테스트 자체가 불가능하다면 만들고 있는 단위를 분리해내서 테스트할순 없는지 생각해봐야할 것입니다. (위에서 말한 View와 Logic의 분리가 이러한 분리의 한 예입니다.)


(류한경) #3

친절한 답변 감사드립니다.

저는 이 인용구에 대해서 이해하지만 왜 최종 렌더링되는 출력 결과를 테스트해야하는지에 관해서는 잘 이해하
지 못하겠습니다.

결국, 화면에 표시되는 수많은 DOM은 애플리케이션 상태에 기반합니다. 애플리케이션에는 수많은 상태가

있으며 Reactjs와 Vuejs와 같은 도구들은 변경된 상태를 감시(변경된 상태가 있는 경우)하여 재 렌더링합니다.

결국 dom은 상태를 기반으로 변경되기 때문에, dom 테스트가 아닌 단순히 모델이나 상태가 이벤트나 함수 호

출에 따라서 어떻게 변화하는지에 관해서 테스트를 진행하면 충분할 것으로 보입니다. (저의 생각에)

정리

최종 렌더링 결과는 상태를 기반으로 합니다. 그래서 상태 변경만 테스트하면 충분할 것으로 현재는 생각됩니다. 최종 랜더링 결과가 동일한가? 와 같은 테스트를 작성하는게 맞을까요?

늘 좋은 답변해주셔서 감사합니다.


(이종은(Jong Lee)) #4

설명이 좀 부족했던 것 같네요. :grinning: 조금 더 자세히 설명해 보겠습니다.

react의 컴포넌트를 테스트한다고 했을 때 컴포넌트의 의미적 결과는 render의 return값입니다. 이 return값을 통해서 실제 DOM에 렌더링하는것은 react의 역할입니다. 제가 말한 부분은 컴포넌트의 props 주었을 때 우리가 원하는 render의 return값이 나오는지를 말했습니다. 이 return값이 실제 browser의 DOM은 아니지만 이 return값으로 react가 VirtualDOM에 반영하고 이를 기반으로 브라우저의 DOM에 반영하겠죠. react가 하는 역할까지는 테스트 할 필요는 없습니다. 단 react에게 넘겨주는 Component의 render 결과물은 우리가 작성한 것이니 테스트 해야한다는 것입니다.

그래서 실제 브라우저의 document를 query하면서 결과를 확인할 필요는 없고 js단에서 component의 output만 확인하면 됩니다. 이런걸 도와주는 도구로 지난번 말씀드린 jest의 snapshot이나 다음 링크에 남기 enzyme등이 있습니다. enzyme은 output의 결과물에 jquery처럼 query를 날려서 output을 검증할 수 있습니다. snapshot은 말그대로 snapshot을 찍어서 이 snapshot의 변화를 확인할 수 있습니다. snapshot은 의도하지 않게 최종 렌더링 결과가 변경되는 부분을 미리 확인할 수 있습니다.

궁금하신 것에 대한 답변이 되었길 바랍니다. :slight_smile:

그래서 상태 변경만 테스트하면 충분할 것으로 현재는 생각됩니다. 최종 랜더링 결과가 동일한가? 와 같은 테스트를 작성하는게 맞을까요?

테스트 하려는 단위의 입력이 무엇이고 출력이 무엇인지를 판단하여 테스트 코드를 작성하면 됩니다. 아래 질문에서 말씀하신 상태 변경만 테스트한다는 것이 어떤 것을 말씀하시는 것인가요? 일단 저는 상태 변경(prop이나 state)에 따른 output(render의 return값)을 변화를 테스트 하는 것에 대해 답변드렸습니다.


(이종은(Jong Lee)) #5

한가지 더 말씀드리자면 실제 dom에 렌더링된 시각적인 모습까지 확인((Visual regression testing)하는 도구들도 있습니다. pixel 단위로 변화를 찾아주는 것이죠. 저는 아직이런 도구를 써보진 않았습니다. 화면이 많이질수록, 그리고 모바일의 경우 다양한 해상도별로 확인해야할 것이 많으니 전부 눈으로 확인하지 말고 이런 도구를 이용하는 것도 좋은 것 같습니다.

UI 컴포넌트의 이런 테스트들을 다음과 같이 구분하게 됩니다. (출처)

  • Visual tests rely on developers to manually look at a component to verify it for correctness. They help us sanity check a component’s appearance as we build.
  • Snapshot tests with Storyshots capture a component’s rendered markup. They help us stay abreast of markup changes that cause rendering errors and warnings.
  • Unit tests with Jest verify that the output of a component remains the same given an fixed input. They’re great for testing the functional qualities of a component.

(류한경) #6

매우 상세한 답변 감사드립니다! 말씀해주신 내용 잘 숙지해서 힘들겠지만 테스트 코드를 작성해보는 경험을

해봐야겠어요. 감사합니다 :smiley: