아래의 발표자료를 저 개인의 이해를 담아 번역해보았습니다.
https://speakerdeck.com/tsuemura/tesutowozi-dong-hua-surufalsewoyame-zi-dong-tesutowozuo-rou
테스트 자동화를 버리고 자동 테스트를 만들어라
- 테스트 자동화 != 자동 테스트
- 테스트 자동화의 성과물 != 자동 테스트
수동 테스트를 소박하게 자동화한다 하여도, 자동 테스트가 되진 않는다.
얘기할 내용들
- 어째서 테스트 자동화는 실패하기 쉬운가.
- 수동 테스트와 그것의 자동화, 그리고 자동 테스트는 어떻게 다른가?
- 자동 테스트란 어떠한 형태여야하는가?
- 수동 테스트의 자동화에는 가치가 없는 것인가?
이번에 주로 얘기하는 테스트는, E2E Test에 대해 서술한다.
어째서 테스트 자동화는 실패하기 쉬운가.
E2E 테스트란?
- 빌드가 끝난 Application에 대해 Web이나 Mobile 기계에서 주로 GUI를 통하여 테스트를 실시하는 것.
- 시스템 테스트라고도 하기도 한다.
- QA (품질보증) 이나 테스터가 수동으로 진행하는 경우가 많음.
테스트 자동화란?
- 주로 수동으로 진행하던 E2E테스트를 자동화 하는 것.
- Selenium, Puppeteer, Cypress, Appium 등
- 주로 실행Cost를 아끼거나 자주 실행하기 위함.
- 부차적으로 테스트 실시자에 의한 판단 미스등을 감소시키기 위함이기도 함.
- 테스트 순서는 수동 테스트의 순서를 재활용한다.
- 개발 플로우 그 자체는 변화지 않는다.
테스트 자동화가 실패하는 자주 있는 패턴
수동으로 열심히 하던 테스트를 자동화하는 것은 좋지만....
- 갑자기 동작하지 않는 경우가 있다. (유지보수 코스트가 높기도 하다)
- Application은 동작하지만 테스트가 실패한다.
- 불안정하여 성공하거나 실패하거나 한다.
- 생각보다 효과가 좋지 않다. (비용대비 효과가 작다)
- 테스트하지 않는 곳에서 버그가 계속나온다.
- 버그의 조기 발견으로는 이어지지 않는다.
수동 테스트를 자동화하는 것으로 인해, 많은 관점들을 확인할 수 없게 됩니다.
자동화된 테스트 코드는 지정된 곳만 확인하기 때문입니다. 예를 들어 로그인할 때 로그인 버튼은 존재 하긴 하지만 CSS나 레이아웃이 깨져있다면 이것은 확인할 수 없습니다.
어째서 자동화한 테스트만이 제대로 동작하지 않게 될까?
- 사실은 Unit Test도 비슷한 일은 많이 있다.
- 다른 것은 개발사이클.
- Unit Test는 개발 도중 에 실시 및 수정된다.
- 자동화 된 테스트는 개발이 다 끝난 후 실시 및 수정된다.
- 애시당초 테스트 하던 패턴이 개발이 끝나고 테스트를 진행해왔기 때문.
- 릴리즈 직전에 테스트가 실행안되는 것을 알게된 경우라면, 테스트하지 않고 그냥 릴리즈할 때가 있다.
- 그 결과 테스트 코드의 유지보수는 나중으로 미루게 된다.
- 실행빈도가 높고, 개발중에도 테스트 실행이 가능하게 된다면, 테스트는 문제없이 돌아갈 확률이 높아진다. 즉, 유지보수를 열심히 해야한다.
단순히 실행 빈도를 높이면 되는 것인가?
- 실행 빈도를 높인다고 해도 문제가 해결되는 것은 아니다.
- 횟수가 아니라 실행환경의 폭을 넓혀야만 한다.
- 예를들어, 애당초 스테이징환경에서만 실행했다면 그것을 개발환경이나 CI환경에서도 실행할 수 있어야 한다.
- 수동 테스트를 단순히 자동화하여도, 전제조건이나 사전 준비는 자동화되지 않는 경우가 많다.
- 특정 환경에 의존한 테스트 케이스가 되어버리기 쉽다.
- 환경이나 특정 테스트 데이터에 의존한다면 개발 사이클과 맞추어 실행하는 것은 어려워진다.
- 의존관계를 해결하고 어느 환경에서던지 실행할 수 있는 테스트를 만들어야 한다.
테스트 자동화와 자동 테스트의 차이
자동 테스트의 일반적인 이미지
- 코드로 작성한다.
- xUnit이나 RSpec등의 테스트 프레임워크를 사용한다.
- TDD나 Refactoring같은 단어를 접한다.
- 안전한 개발을 위해 만든다는 이미지가 있다.
- 그냥 어찌되었던간에 QA나 Tester가 실시하는 것과는 다른 스멜이 난다.
자동 테스트와 타입 검사, Linter
- 자동 테스트 : Application이 기대한 동작을 하지 않으면 릴리즈할 수 없다.
- 타입 검사 : 데이터 타입에 부정합이 있다면 빌드를 할 수 없다. (컴파일 / 빌드 실패)
- Linter : 부적절한 코드작성법이라면 경고를 노출한다.
즉 각각의 테스트들은 담당 기능에서 강제성을 띈다.
Application과 자동 테스트의 관계
- 둘 다 Product의 일부.
- 둘 다 Specification을 구현한 것.
- Application은 그 자체로는 큰 의미가 없고, 누군가가 사용할때야 말로 가치가 생김.
- Application은 동작을 구현한 것.
- 자동 테스트는 해당 Application의 사용방법을 구현한 것.
- 자동 테스트는 Application을 속박한다.
- Application의 특정 동작에 의존하는 것으로, 해당 동작을 속박한다. (해당 동작을 하지 않는다면 테스트 실패.)
- 각각 코드로 작성되어져 있고, 실행가능한 형태로 기술되어져 있어 강제력을 발휘한다.
자동 테스트란 ?
- Product의 일부이며 동시에 개발된다.
- 개발 사이클이 한창일때 개발된다. (Test 공정에서의 자동화가 아니다.)
- Application의 동작에 매우 밀접하게 의존한다.
- 정적 소스코드 검사 등과 마찬가지로 빈번하게 실행되어 Specification과 맞지 않게 되는 것을 항상 방지한다.
소박한 테스트 자동화는 부분적인 변화만 가져올 뿐이다.
- | 수동 테스트 | 테스트 자동화 | 자동 테스트 |
---|
개발 사이클 | 개발과는 별개 | 개발과는 별개 | 개발과 동시 진행 |
실행 빈도 | 적음 | 적음 | 많음 |
실행 순서 | 애매하며 암묵적 | 엄밀하며 구체적 | 엄밀하며 구체적 |
검증 방법 | 발견적인 경우가 많음 | 코드의 체크포인트에 의해 보증되어있음. | 코드의 체크포인트에 의해 보증되어있음. |
우리가 정말로 원하는 것은 무엇일까?
테스트 자동화의 동기
- 인간이기 때문에 발생하는 문제로부터의 해방
- 단순 작업으로부터의 해방
- 리소스 부족의 해결
- 이른바 속인화 라고 하는, 특정 인원에게 의존적인 상황의 해결
- 고속화, 고 빈도화
- Release 속도의 향상
- 언제든지 테스트 가능
- Refactoring
어째서 테스트 자동화로는 고속, 고빈도 실행이 실현되지 않는가?
고빈도화를 위한 시나리오 최적화
수동 테스트에 최적화된 상태.
- 어떤 테스트로 만들어진 데이터를 다른 테스트에서 재이용하는 것.
- 신규작성 시나리오에서 생성한 데이터를 업데이트 에서 재이용
- 특정 환경에서만 존재하는 테스트용 데이터를 사용하는 것.
자동 테스트에 최적화시킬 것.
CI로의 실행이나 동시 실행 등을 가능하게 하기 때문.
- 항상 새로운 데이터를 만들 것.
- GUI가 아닌 API나 Command로 생성할 것.
- 실행이 다른 테스트에 영향을 미치지 ㅇ낳을 것.
- 예를 들어 테스트 데이터 생성 시의 랜덤한 문자열을 사용하는 등.
- 환경 의존 부분을 배제할 것.
자동 테스트 스러운 테스트 자동화
- 개발중에도 여러가지 환경에서 테스트.
- 높은 빈도로 (commit이나 Push될 때) 실행되어 버그를 방지.
- 안전성이 높다.
- 다른 테스트 시나리오로부터 영향을 받지 않는다.
- 몇번이고 동시에 실행하여도 문제없다.
- 테스트 시나리오가 자주 유지보수된다.
- 테스트 관점 이외의 조작은 API나 Command로 조작한다.
고빈도화는 실현되었다고 쳐도, Human-error로부터는 해방되었는가...?
자동화 코드를 작성하여도 오히려 유지보수 등을 포함한 업무가 추가되었기 때문에, 사람이 편해지진 않는다.
어느정도 두루뭉술 한 테스트도 필요하다.
자동 테스트에서는 놓치는 것들이 있다.
- 환경 의존적인 데이터에 의존적인 것들은 찾아낼 수 없다.
- 예) 대량의 관련 데이터를 가진 유저만 정상적으로 동작한다.
- Assertion을 사용하지 않은 부분은, 찾아낼 수 없다.
- 누가봐도 이상한 부분이지만, 코드에서는 검출할 수 없는 부분.
- 특히 레이아웃 깨짐에 취약하다.
애당초 빡세게 요소요소 확인하는 것은 E2E 다운 방식이 아니다.
- 빡빡하게 만든 테스트에서 검증할 수 있는 것은 어느정도 확실한 초점/관점으로 포인트를 맞춘 테스트
- E2E는 애당초 여러 환경에서 있을 수 있는 리얼한 환경에서의 테스트가 목적.
- 리얼한 환경에서 문제없는 것 처럼 동작하는 것을 확인하는 것이 바람직.
두루뭉술한 자동테스트는 실현 가능한가?
빡빡하게 체크하는 코드보다는 대충 확인하는 코드가 필요할지도.
$('#username').click()
$('[data-test=username]').click();
// 보다는 아래 코드라면, 레이아웃이 깨진다던지 내용이 표시안된다던지 하는 것을 체크할 수 있을지도.
$('유저 이름').click();
문언이나 구조에 따른 의미 있는 로케이터.
xx라는 메세지를 표시하고 있는 모달의 안에 yy라는 버튼
과 같은 구조를 지정한다면...?
AI에 의한 요소 검색 등.
여러개의 로케이터를 찾아내서 AI로 파악하는 등의 테스트.
두루뭉술한 검증
- Assertion 지옥에서 도망쳐야한다.
- 체크포인트를 하나하나 지정한다면 그만큼 유지보수 지옥이 된다는 것.
- 사람이 보고 단번에 알 수 있는 레벨의 issue를 회피하는 것이 목적
- 표시되어야하는 것이 표시되지 않는다던지
- 레이아웃이 깨진다던지.
화면비교 (Visual-Regression)
- 테스트 실행할 때마다 screenshot을 capture하여 비교.
- 스타일이나 레이아웃이 깨져있진 않는지 확인.
- 비교 대상에서 제외할 부분은 별도로 정의가 필요.
- 좌표보정이 필요.
꼼꼼하고 빡빡하게 체크하는 것과, 두루뭉술하고 확인하는 것 중 어느쪽이 좋을까?
버그는 되도록 상위단계에서 잡아내는 것이 좋고, 그물망처럼 아랫단계에도 테스트를 한다는 개념이 좋음.
꼼꼼하고 빡빡한 테스트
두루뭉술한 테스트
- 호환성 (Cross-browser, multi-device) 테스트
- use-case test
- smoke test
결론
- 수동 테스트를 소박하게 자동화하여도, 자동테스트가 되진 않는다.
- 소박한 테스트 자동화는 자동화한 것 만큼의 효과도 없을 수 있다.
- 신규 버그는 찾을 수 없고, 오히려 유지보수 코스트가 증가하게 된다.
- 자동 테스트는, 빡빡하고 꼼꼼한 자동테스트와, 수동 테스트와 비슷하게 두루뭉술하게 하는 자동테스트가 있다.
- 테스트 자동화를 목표로 하는 것이 아닌, Entry-point로서 자동 테스트에 입문하여 더욱 발전시켰으면 좋겠다.
ref
잘 보고 갑니데이