• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

4.4 통합테스트에서 정적 데이터로 테스트하는 대신 role 값을 미리 설정해 직접 돔에 접근하는 방식은 어떤가요?

24.02.22 13:02 작성 조회수 165

1

안녕하세요우선 좋은 강의를 제작해주셔서 감사드립니다공식 문서만으로 테스트 코드 작성을 공부했다면 훨씬 시간이 많이 들었을 텐데한글로 설명을 듣고 문서를 보니 좀 더 빠르게 이해할 수 있는 것 같습니다. // answer 브랜치 코드 it('특정 아이템의 수량이 변경되었을 때 값이 재계산되어 올바르게 업데이트 된다', async () => { const { user } = await render(<ProductInfoTable />); const [firstItem] = screen.getAllByRole('row'); const input = within(firstItem).getByRole('textbox'); await user.clear(input); await user.type(input, '5'); // 2427 + 809 * 2 = 4045 expect(screen.getByText('$4,045.00')).toBeInTheDocument(); });궁금한 점은 현재 제공해주신 정답 코드에서는모킹 데이터의 결과 포맷을 알기 때문에 '$4,045.00' 이라는 텍스트 값이 dom에 마운트 되어야 테스트를 통과 시키는 방식인데요 it('특정 아이템의 수량이 변경되었을 때 값이 재계산되어 올바르게 업데이트 된다', async () => { const { user } = await render(<ProductInfoTable />); const [firstItem] = screen.getAllByRole('row'); const input = within(firstItem).getByRole('textbox'); // role은 price를 담는 div에 미리 추가했다고 가정 const price = Number(within(firstItem).getByRole('price').textContent); const value = 5; await user.clear(input); await user.type(input, value.toString()); const pricedResult = within(firstItem).getByRole('price').textContent; // 2427 + 809 * 2 = 4045 expect(priceResult.includes((value*price).toLocaleString())).toBe(true); });제가 작성한 방식은엘리먼트마다 role을 미리 지정해 둔 다음에테스트할 때마다 element들의 값에 접근해서 테스트를 진행하는 방식입니다.제가 생각했을 때에는 이 방식을 사용하면 element마다 role을 직접 설정해주어 element의 용도를 파악하기 더 쉽고 getAllBy... 메소드로 가져온 요소들에 대해 순회하여 테스트할 때 테스트 결과 값을 동적으로 생성하기 때문에 더 유연하지 않을까 라는 생각이 들었습니다. 궁금한 점은 제가 작성한 방식을 현업에서도 사용하는지잘 사용되지 않는 방식이라면 어떤 이유에서 잘 사용되지 않는지가 궁금합니다

답변 1

답변을 작성해보세요.

1

안녕하세요 Nani 님~! 우선 강의가 도움이 되신다고 하니 감사합니다 🙂

DOM에 직접 role을 부여하여 테스트 하면 동적인 결과값을 검증하기 더 편리하지 않은지 문의 주신걸로 이해되는대요.

저희가 role을 강제로 부여하지 않고 예제처럼 테스트를 작성한 이유는 크게 두가지가 있는대요.

  • 우선 통합 테스트에서는 모킹 데이터 기반으로 테스트를 실행하기 때문에 특정 컴포넌트를 렌더링했을때 모킹 데이터 기준으로 원하는 기대값을 알고 검증할 수 있습니다. 이때 $4,045.00처럼 구체적인 기대값을 쓰는 이유는 특정 DOM 구조에 의존하지 않고 정확히 연산된 기대값이 무엇인지 확인하기 위함입니다. Number(within(firstItem).getByRole('price').textContent) 로 작성하면 동적인 계산 결과를 대응할 수 있지만, price란 role을 가진 요소에 계산 결과를 의존하게 됩니다. 해당 요소가 사라지거나 변경되면 테스트가 깨질 수 있으며, 계산 결과는 DOM의 특정 값에 의존하는게 아니라 실제 데이터에 의존하여 계산되는 것이기 때문에 모킹 데이터 기준으로 연산한 $4,045.00 값이 있는지를 검증하였습니다.

  • 두번째로 role이란 속성은 W3C에서 웹 접근성을 위해 특정 요소마다 부여한 스펙인대요. 특별한 상황이 아니면 특정 요소의 role을 강제로 부여하는 것은 웹의 시맨틱 정의에 어긋날 수 있습니다. 이로 인해 스크린 리더나 탭키의 동작, 웹 크롤러가 HTML을 수집할 때도 영항을 줄 수 있는대요. 이런 이슈때문에 별도의 role을 설정해서 검증하지 않았고, 만약 특정 요소 대상으로 testing library의 쿼리를 사용하고 싶다면 testid를 사용하는 것을 공식적으로 권장하고 있습니다.

위의 2가지 이유로 role을 직접 부여하지 않고 테스트를 작성하였습니다.

혹시 설명이 부족하거나 다른 궁금한 부분이 있다면 얼마든지 편하게 말씀해주세요.

감사합니다!

Nani님의 프로필

Nani

질문자

2024.02.23

답변 감사드립니다!

 

테스트는 한 가지 기능이 잘 동작하는지만 보면 되기 때문에

데이터에 의존적인 동적인 방법 보다는

정적인 데이터로 정확하게 동작하는지 확인하는게 더 본래의 목적에 맞다고

이해했습니다.

 

제가 이해한게 맞게 이해한 걸까요?

안녕하세요 Nani님~!

한가지 기능을 검증한다는 것은 동적인 데이터를 사용해도 정적인 데이터를 사용해도 데이터만 달라질뿐 동일한대요.

다만, A input을 입력했을때 기대한 B output이 나오는지 명확하게 검증하기 위해 정적인 데이터 셋을 사용했습니다. 이렇게 정적인 데이터를 사용하면 계산식 자체에 문제가 있는 경우까지 테스트를 통해 인지하고 검증할 수 있어 좀 더 높은 안정성을 보장할 수 있습니다.

아래는 예제와는 조금 다르지만.. calculateValue()처럼 계산 과정이 별도 함수로 추출되어 있는 경우 calculateValue()함수를 그대로 사용하여 컴포넌트에 렌더링되는 기대값을 검증해버리면 calculateValue()함수의 계산식 자체에 문제가 있을 경우는 검증하지 못합니다.

function calculateValue(value) {
  // ...
}

// calculateValue() 함수의 로직이 잘못되었을 경우 검증할 수 없다.
expect(result).toBe(calculateValue(value));

expect(result).toBe('$3,000');

개인적으로 이러한 휴먼 에러를 조금이나마 방지하고자 이미 명확하게 만들어진 정적인 데이터로 테스트를 작성하고 있습니다. 예제에서도 이런 의도를 갖고 명확한 데이터로 검증하도록 테스트를 작성하였습니다!