분류 Reactjs

UI 테스트를 탄력적으로 변경하여 변경

컨텐츠 정보

  • 조회 281 (작성일 )

본문

사용자 인터페이스 테스트는 매우 까다 롭고 파손되기 쉽습니다. 이것을 개선하는 방법에 대해 이야기합시다.


개발자는 로그인 경험이 깨지는 것을 피하기 위해 몇 가지 테스트를 작성하여 그렇지 않은지 확인합니다. 이러한 양식의 예를 간단히 살펴 보겠습니다.


https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change 


Login form from the Bookshelf App 


const form = (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">Username</label>
<input id="username" className="username-field" />
</div>
<div>
<label htmlFor="password">Password</label>
<input id="password" type="password" className="password-field" />
</div>
<div>
<button type="submit" className="btn">
Login
</button>
</div>
</form>
)

이제 이 양식을 테스트하려면 사용자 이름, 비밀번호를 입력하고 양식을 제출하십시오. 이를 제대로 수행하려면 양식을 렌더링하고 문서를 쿼리하여 해당 노드를 찾아서 작동해야 합니다. 그렇게 하기 위해 시도 할 수 있는 작업은 다음과 같습니다.


const usernameField = rootNode.querySelector('.username-field')
const passwordField = rootNode.querySelector('.password-field')
const submitButton = rootNode.querySelector('.btn')

여기에 문제가 발생합니다. 다른 버튼을 추가하면 어떻게 됩니까? "로그인"버튼 앞에 "가입"버튼을 추가하면 어떻게 됩니까?


const form = (
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="username">Username</label>
<input id="username" className="username-field" />
</div>
<div>
<label htmlFor="password">Password</label>
<input id="password" type="password" className="password-field" />
</div>
<div>
<button type="submit" className="btn">
Sign up
</button>
<button type="submit" className="btn">
Login
</button>
</div>
</form>
)

Whelp, 테스트를 중단 할 것입니다. 그러나 그것은 바로 고치기가 꽤 쉬울까요?


// change this:
const submitButton = rootNode.querySelector('.btn')
// to this:
const submitButton = rootNode.querySelectorAll('.btn')[1]

그리고 우리는 가도 좋습니다! 글쎄, 우리가 CSS-in-JS를 사용하여 양식을 스타일링하고 더 이상 username-field와 password-field 클래스 이름이 필요하지 않다면 제거해야 합니까? 또는 테스트에서 사용하기 때문에 유지합니까? 흠 ...?


그렇다면 어떻게 탄력적인 선택자를 작성합니까? 


"귀하의 테스트가 소프트웨어 사용 방식과 유사할수록 더 많은 신뢰를 줄 수 있다"는 점을 감안할 때 사용자가 클래스 이름을 신경 쓰지 않는다는 사실을 고려하는 것이 좋습니다.


팀에 수동 테스터가 있고 페이지를 테스트 하기 위한 지침을 작성한다고 가정 해 봅시다. 그 지시 사항은 무엇입니까?


  1. 클래스 이름 username-field를 가진 요소를 얻는다
  2. ...

"잠깐만 요." "클래스 이름 username-field를 가진 요소를 어떻게 찾을 수 있습니까?"


"아, 그냥 devtools를 열고 ..."


"그러나 우리의 사용자들은 그렇게 하지 않을 것입니다. 왜 username이라는 라벨이 있는 필드를 찾지 못하겠습니까?"


"아, 그래, 좋은 생각이야."


이것이 테스팅 라이브러리가 수행하는 쿼리를 갖는 이유입니다. 쿼리는 사용자가 찾을 때와 같은 방식으로 요소를 찾는 데 도움이 됩니다. 이러한 쿼리를 사용하면 레이블, 자리 표시 자, 텍스트 내용, 대체 텍스트, 제목, 표시 값, 역할, 테스트 ID별로 요소를 찾을 수 있습니다.


실제로 권장 순서대로 되어 있습니다. 이러한 접근 방식에는 확실히 상충 관계가 있지만 이러한 쿼리를 사용하여 수동 테스터에 대한 지침을 작성하면 다음과 같이 보일 것입니다.

  1. 입력 한 username에 가짜 사용자 이름을 입력하십시오.
  2. 입력 한 password에 가짜 비밀번호를 입력하십시오.
  3. sign in 텍스트가 있는 버튼을 클릭하십시오

또한 소프트웨어를 가능한 한 사용하는 방식에 가깝게 테스트하고 있는지 확인하는 데 도움이 됩니다. 테스트에서 더 많은 가치를 제공합니다.


data-testid 쿼리는 무엇입니까? 


때로는 다른 쿼리로 요소를 안정적으로 선택할 수 없는 경우가 있습니다. 이를 위해서는 data-testid를 사용하는 것이 좋습니다 (물론 적절한 역할 속성이나 다른 것을 먼저 사용하는 것을 잊지 않도록 해야 합니다).


이 상황에 처한 많은 사람들이 왜 getByClassName 쿼리를 포함 시키지 않는지 궁금합니다. 선택기에 클래스 이름을 사용하는 것이 마음에 들지 않는 것은 일반적으로 클래스 이름을 스타일을 지정하는 방법으로 생각한다는 것입니다. 따라서 목적에 맞지 않는 클래스 이름을 추가하기 시작하면 클래스 이름이 무엇인지, 언제 클래스 이름을 제거 할 수 있는지 알기가 더욱 어려워집니다.


스타일링에 이미 사용하고 있는 클래스 이름을 재사용 하려고 하면 위의 버튼과 같은 문제가 발생합니다. 기능을 리팩터링하거나 추가 할 때 테스트를 변경해야 할 때마다 취성 테스트를 나타냅니다. 핵심 문제는 테스트와 소스 코드 간의 관계가 너무 암시 적이라는 것입니다. 우리가 그 관계를 보다 분명하게 만들면 이 문제를 극복 할 수 있습니다.


요소에 메타 데이터를 추가 할 수 있다면 문제를 해결할 수 있도록 선택하려고 합니다. 잘 생각 해봐! 실제로 기존 API가 있습니다! data- 속성입니다! 예를 들면 다음과 같습니다.


function UsernameDisplay({user}) {
return <strong data-testid="username">{user.username}</strong>
}

그런 다음 테스트에서 다음과 같이 말할 수 있습니다.


const usernameEl = getByTestId('username') 


이것은 엔드-투-엔드 테스트에도 좋습니다. 그래서 당신도 그것을 사용하는 것이 좋습니다! 그러나 일부 사람들은 이러한 속성을 프로덕션으로 배송하는 것에 대해 우려를 표명했습니다. 그것이 당신이라면, 실제로 그것이 당신에게 문제인지 아닌지를 고려하십시오 (정직하게 생각하는 것만 큼 큰 문제는 아니기 때문에). 정말로 원한다면 babel-plugin-react-remove-properties를 사용하여 해당 속성을 컴파일 할 수 있습니다.


결론 


소프트웨어 사용 방법과 유사한 방식으로 응용 프로그램을 테스트하면 변경에 대한 테스트의 탄력성이 높아질 뿐만 아니라 더 많은 가치를 얻을 수 있습니다. 이것에 대해 더 배우고 싶다면 내 블로그 게시물 테스팅 구현 세부 사항에서 더 많은 것을 읽으십시오.