비정상적 테스트: 테스트에서 살아있는 악몽 제거하기

게시 됨: 2022-03-10
빠른 요약 ↬ 신뢰할 수 없는 테스트는 자동화된 테스트를 작성하거나 결과에 주의를 기울이는 모든 사람에게 살아있는 악몽입니다. 비정상적 테스트는 사람들에게 악몽과 잠 못 이루는 밤을 주기까지 했습니다. 이 기사에서 Ramona Schwering은 이 지옥에서 벗어나거나 지옥에 빠지지 않도록 돕기 위해 그녀의 경험을 공유합니다.

요즘 많이 생각나는 우화가 있습니다. 그 우화는 어렸을 때 나에게 들려주었다. 이솝의 '늑대를 우는 소년'이라는 곡입니다. 마을의 양들을 돌보는 소년의 이야기입니다. 그는 지루해져서 늑대가 양떼를 공격하는 척하며 마을 사람들에게 도움을 요청합니다. 그러나 실망스럽게도 그것이 거짓 경보임을 깨닫고 소년을 내버려 두었습니다. 그러다가 실제로 늑대가 나타나 소년이 도움을 요청하자 마을 사람들은 또 다른 오경보라고 믿고 구출에 오지 않고 양들은 결국 늑대에게 잡아먹힌다.

이야기의 교훈은 저자 자신이 가장 잘 요약한 것입니다.

“거짓말쟁이는 진실을 말하더라도 믿지 않을 것이다.”

늑대가 양을 공격하고 소년은 도움을 요청하지만 수많은 거짓말 후에 더 이상 그를 믿는 사람이 없습니다. 이 교훈은 테스트에 적용될 수 있습니다. Aesop의 이야기는 내가 우연히 발견한 매칭 패턴에 대한 좋은 비유입니다. 가치를 제공하지 못하는 비정상적 테스트입니다.

프론트엔드 테스팅: 왜 귀찮은가?

내 하루의 대부분은 프론트 엔드 테스트에 소비됩니다. 따라서 이 기사의 코드 예제가 대부분 제가 작업하면서 접한 프론트 엔드 테스트에서 가져온 것이라는 사실에 놀라지 마십시오. 그러나 대부분의 경우 다른 언어로 쉽게 번역되어 다른 프레임워크에 적용할 수 있습니다. 따라서 이 기사가 귀하에게 유용하기를 바랍니다.

프런트 엔드 테스트가 의미하는 바를 상기할 가치가 있습니다. 본질적으로 프론트 엔드 테스트는 기능을 포함하여 웹 애플리케이션의 UI를 테스트하기 위한 일련의 관행입니다.

품질 보증 엔지니어로 시작하여 릴리스 직전에 체크리스트에서 끝없는 수동 테스트의 고통을 알고 있습니다. 따라서 연속적인 업데이트 동안 응용 프로그램이 오류가 없는 상태를 유지한다는 목표 외에도 실제로 사람이 필요하지 않은 일상적인 작업으로 인해 발생하는 테스트의 워크로드를 완화하기 위해 노력했습니다. 이제 개발자로서 특히 사용자와 동료를 모두 직접 도우려고 할 때 주제가 여전히 관련성이 있음을 알게 되었습니다. 그리고 특히 우리에게 악몽을 안겨준 한 가지 테스트 문제가 있습니다.

비정상적 테스트의 과학

비정상적 테스트는 동일한 분석이 실행될 때마다 동일한 결과를 생성하지 못하는 테스트입니다. 빌드는 가끔씩만 실패합니다. 한 번은 통과하고 다른 한 번은 실패하고 다음 번에는 빌드를 변경하지 않고 다시 통과합니다.

악몽 같은 테스트를 떠올리면 특히 한 가지 사례가 떠오릅니다. UI 테스트 중이었습니다. 사용자 지정 스타일의 콤보 상자(즉, 입력 필드가 있는 선택 가능한 목록)를 만들었습니다.

사용자 지정 선택기의 예
매일 작업한 프로젝트의 사용자 지정 선택기. (큰 미리보기)

이 콤보 상자를 사용하여 제품을 검색하고 하나 이상의 결과를 선택할 수 있습니다. 여러 날 동안 이 테스트는 정상적으로 진행되었지만 어느 시점에서 상황이 바뀌었습니다. CI(지속적 통합) 시스템의 약 10개 빌드 중 하나에서 이 콤보 상자에서 제품을 검색하고 선택하는 테스트가 실패했습니다.

실패 스크린샷은 검색이 성공했음에도 불구하고 필터링되지 않은 결과 목록을 보여줍니다.

불안정한 테스트가 포함된 CI 실행의 스크린샷
작동 중인 비정상적 테스트: 항상 그런 것은 아니고 가끔만 실패하는 이유는 무엇입니까? (큰 미리보기)

이와 같은 불안정한 테스트 는 지속적인 배포 파이프라인을 차단하여 기능 제공을 필요한 것보다 느리게 만들 수 있습니다. 게다가, flaky test는 더 이상 결정적이지 않아 쓸모가 없기 때문에 문제가 됩니다. 결국, 당신은 거짓말쟁이를 신뢰하는 것보다 더 이상 누군가를 신뢰하지 않을 것입니다.

또한, 비정상적 테스트는 수리 비용 이 많이 들고 디버그하는 데 몇 시간 또는 며칠이 소요되는 경우가 많습니다. 종단 간 테스트가 더 취약하기는 하지만 단위 테스트, 기능 테스트, 종단 간 테스트 및 그 사이의 모든 것 등 모든 종류의 테스트에서 이러한 테스트를 경험했습니다.

비정상적 테스트의 또 다른 중요한 문제는 이것이 우리 개발자에게 부여하는 태도입니다. 테스트 자동화 분야에서 일하기 시작했을 때 개발자들이 실패한 테스트에 대해 다음과 같이 말하는 것을 종종 들었습니다.

“아, 그 빌드. 신경 쓰지 말고 다시 시작하십시오. 언젠가는 결국 지나갈 것입니다.”

이것은 저에게 큰 위험 신호 입니다. 빌드의 오류가 심각하게 받아들여지지 않을 것임을 보여줍니다. 비정상적 테스트는 실제 버그가 아니라 "그냥" 비정상적이며 처리하거나 디버깅할 필요도 없다는 가정이 있습니다. 어쨌든 나중에 테스트는 다시 통과하겠죠? 아니요! 그러한 커밋이 병합되면 최악의 경우 제품에서 새로운 불안정한 테스트가 발생합니다.

점프 후 더! 아래에서 계속 읽기 ↓

원인

따라서 비정상적 테스트가 문제가 됩니다. 우리는 그들에 대해 어떻게 해야 합니까? 문제를 안다면 대응 전략을 세울 수 있습니다.

나는 일상 생활에서 종종 원인을 만난다. 그것들은 테스트 자체에서 찾을 수 있습니다. 테스트는 차선책으로 작성되거나 잘못된 가정을 유지하거나 나쁜 관행을 포함할 수 있습니다. 그러나 그뿐만이 아닙니다. 비정상적 테스트는 훨씬 더 나쁜 것을 나타낼 수 있습니다.

다음 섹션에서는 내가 접한 가장 일반적인 항목을 살펴보겠습니다.

1. 테스트 측 원인

이상적인 세계에서 애플리케이션의 초기 상태는 깨끗하고 100% 예측 가능해야 합니다. 실제로 테스트에 사용한 ID가 항상 동일한지 여부는 알 수 없습니다.

내 부분에서 단일 실패의 두 가지 예를 살펴보겠습니다. 첫 번째 실수는 내 테스트 픽스처에서 ID를 사용하는 것이었습니다.

 { "id": "f1d2554b0ce847cd82f3ac9bd1c0dfca", "name": "Variant product", }

두 번째 실수는 UI 테스트에서 사용할 고유 선택기 를 검색하고 "오케이, 이 ID가 고유한 것 같습니다. 사용하겠습니다.”

 <!-- This is a text field I took from a project I worked on --> <input type="text" />

그러나 다른 설치 또는 나중에 CI의 여러 빌드에서 테스트를 실행하면 해당 테스트가 실패할 수 있습니다. 우리 애플리케이션은 ID를 새로 생성하여 빌드 간에 변경합니다. 따라서 첫 번째 가능한 원인은 하드코딩된 ID 에서 찾을 수 있습니다.

두 번째 원인은 무작위로(또는 다른 방식으로) 생성된 데모 데이터 에서 발생할 수 있습니다. 물론 이 "결함"이 정당하다고 생각할 수도 있습니다. 결국 데이터 생성은 무작위로 이루어지지만 이 데이터를 디버깅하는 것에 대해 생각해 보십시오. 버그가 테스트 자체에 있는지 아니면 데모 데이터에 있는지 확인하는 것은 매우 어려울 수 있습니다.

다음은 내가 여러 번 고심했던 테스트 측 원인입니다. 바로 교차 종속성이 있는 테스트입니다 . 일부 테스트는 독립적으로 또는 임의의 순서로 실행할 수 없어 문제가 될 수 있습니다. 또한 이전 테스트가 후속 테스트를 방해할 수 있습니다. 이러한 시나리오는 부작용을 도입하여 불안정한 테스트를 유발할 수 있습니다.

그러나 테스트는 도전적인 가정 에 관한 것임을 잊지 마십시오. 처음부터 가정에 결함이 있으면 어떻게 됩니까? 나는 이것을 자주 경험했는데, 내가 가장 좋아하는 것은 시간에 대한 잘못된 가정이었습니다.

한 가지 예는 특히 UI 테스트에서 부정확한 대기 시간을 사용하는 것입니다(예: 고정 대기 시간 사용). 다음 줄은 Nightwatch.js 테스트에서 가져온 것입니다.

 // Please never do that unless you have a very good reason! // Waits for 1 second browser.pause(1000);

또 다른 잘못된 가정은 시간 자체와 관련이 있습니다. 나는 한 번 불안정한 PHPUnit 테스트가 야간 빌드에서만 실패한다는 것을 발견했습니다. 약간의 디버깅 후에 어제와 오늘 사이의 시간 이동이 원인임을 발견했습니다. 또 다른 좋은 예는 시간대 로 인한 실패입니다.

잘못된 가정은 여기서 그치지 않습니다. 데이터의 순서에 대해 잘못된 가정을 할 수도 있습니다. 통화 목록과 같은 정보가 포함된 여러 항목이 포함된 그리드 또는 목록을 상상해 보십시오.

우리 프로젝트에서 사용되는 사용자 지정 목록 구성 요소
우리 프로젝트에서 사용되는 사용자 지정 목록 구성 요소입니다. (큰 미리보기)

우리는 첫 번째 항목인 "체코 코루나" 통화의 정보로 작업하고 싶습니다. 테스트가 실행될 때마다 애플리케이션이 항상 이 데이터 조각을 첫 번째 항목으로 배치할 것이라고 확신할 수 있습니까? 경우에 따라 "유로" 또는 다른 통화 가 첫 번째 항목이 될 수 있습니까?

데이터가 필요한 순서대로 올 것이라고 가정하지 마십시오. 하드코딩된 ID와 유사하게 애플리케이션 디자인에 따라 빌드 간에 순서가 변경될 수 있습니다.

2. 환경적 원인

원인의 다음 범주는 테스트 이외의 모든 것과 관련됩니다. 특히 테스트가 실행되는 환경, 테스트 외부의 CI 및 도커 관련 종속성에 대해 이야기하고 있습니다. 최소한 테스터로서의 역할에서는 거의 영향을 미칠 수 없는 모든 것입니다.

일반적인 환경 측 원인은 리소스 누수 입니다. 종종 이것은 로드 중인 응용 프로그램으로 인해 다양한 로드 시간이나 예기치 않은 동작이 발생합니다. 대규모 테스트는 쉽게 누수를 일으켜 많은 메모리를 차지할 수 있습니다. 또 다른 일반적인 문제는 정리가 부족하다는 것입니다 .

종속성 간의 비호환성은 특히 나에게 악몽을 줍니다. UI 테스트를 위해 Nightwatch.js로 작업할 때 악몽이 하나 발생했습니다. Nightwatch.js는 물론 Chrome에 의존하는 WebDriver를 사용합니다. Chrome이 업데이트를 앞당겼을 때 호환성 문제가 있었습니다. Chrome, WebDriver 및 Nightwatch.js 자체가 더 이상 함께 작동하지 않아 빌드가 때때로 실패했습니다.

종속성에 대해 말하기 : 권한 누락 또는 npm 작동 중지와 같은 모든 npm 문제에 대해 명예 멘션이 적용됩니다. 저는 CI를 관찰하면서 이 모든 것을 경험했습니다.

환경 문제로 인해 UI 테스트에서 오류가 발생하는 경우 전체 애플리케이션 스택이 실행되어야 한다는 점을 염두에 두십시오. 관련된 것들이 많을수록 오류 가능성이 커 집니다. 따라서 JavaScript 테스트는 많은 양의 코드를 다루기 때문에 웹 개발에서 안정화하기 가장 어려운 테스트입니다.

3. 제품측 원인

마지막으로 우리는 세 번째 영역인 실제 버그가 있는 영역에 대해 정말 주의해야 합니다. 나는 벗겨짐의 제품 측 원인에 대해 이야기하고 있습니다. 가장 잘 알려진 예 중 하나는 애플리케이션의 경쟁 조건 입니다. 이런 일이 발생하면 테스트가 아닌 제품에서 버그를 수정해야합니다! 이 경우 테스트나 환경을 수정하려고 해도 아무 소용이 없습니다.

벗겨짐과 싸우는 방법

우리는 박편의 세 가지 원인을 확인했습니다. 우리는 이에 대한 대응 전략을 세울 수 있습니다! 물론, 불안정한 테스트에 직면했을 때 세 가지 원인을 염두에 두면 이미 많은 것을 얻었을 것입니다. 무엇을 찾아야 하고 테스트를 개선하는 방법을 이미 알고 있을 것입니다. 그러나 이것 외에도 테스트를 설계, 작성 및 디버그하는 데 도움이 되는 몇 가지 전략이 있으며 다음 섹션에서 함께 살펴보겠습니다.

팀에 집중

당신의 팀은 틀림없이 가장 중요한 요소 입니다. 첫 번째 단계로 불안정한 테스트에 문제가 있음을 인정하십시오. 전체 팀의 헌신을 얻는 것이 중요합니다! 그런 다음 팀으로서 불안정한 테스트를 처리하는 방법을 결정해야 합니다.

기술 분야에서 일하면서 팀에서 사용하는 4가지 전략을 접했습니다.

  1. 아무 것도 하지 않고 비정상적 테스트 결과를 수락하십시오.
    물론 이 전략은 전혀 해결책이 아닙니다. 테스트는 더 이상 신뢰할 수 없기 때문에 가치가 없습니다. 그래서 우리는 이것을 아주 빨리 건너뛸 수 있습니다.
  2. 통과할 때까지 테스트를 다시 시도합니다.
    이 전략은 내 경력 초기에 일반적이었으며 앞서 언급한 응답으로 이어졌습니다. 통과할 때까지 테스트를 다시 시도하여 일부 승인이 있었습니다. 이 전략은 디버깅이 필요하지 않지만 게으릅니다. 문제의 증상을 숨기는 것 외에도 테스트 제품군의 속도가 훨씬 느려져 솔루션이 실행 가능하지 않게 됩니다. 그러나 이 규칙에는 몇 가지 예외가 있을 수 있으며 나중에 설명하겠습니다.
  3. 테스트를 삭제하고 잊어버리십시오.
    이것은 자명합니다. 더 이상 테스트 스위트를 방해하지 않도록 비정상적 테스트를 삭제하기만 하면 됩니다. 물론 더 이상 테스트를 디버그하고 수정할 필요가 없기 때문에 비용을 절약할 수 있습니다. 그러나 약간의 테스트 범위를 잃고 잠재적인 버그 수정을 잃게 됩니다. 테스트는 이유가 있습니다! 테스트를 삭제하여 메신저를 쏘지 마십시오.
  4. 격리하고 수정합니다.
    나는 이 전략으로 가장 큰 성공을 거두었다. 이 경우 일시적으로 테스트를 건너뛰고 테스트 스위트가 테스트를 건너뛰었음을 지속적으로 상기시키도록 합니다. 수정 사항이 간과되지 않도록 다음 스프린트 티켓을 예약합니다. 봇 알림도 잘 작동합니다. 벗겨짐을 유발하는 문제가 수정되면 테스트를 다시 통합(즉, 건너뛰기 취소)할 것입니다. 유감스럽게도 일시적으로 적용 범위를 잃게 되지만 수정 사항을 통해 다시 돌아올 것이므로 오래 걸리지 않을 것입니다.
CI 보고서에서 가져온 테스트 건너뛰기
CI의 보고서에서 가져온 테스트를 건너뛰었습니다. (큰 미리보기)

이러한 전략은 워크플로 수준에서 테스트 문제를 처리하는 데 도움이 되며 나 혼자만이 문제가 발생한 것은 아닙니다. 그의 기사에서 Sam Saffron은 비슷한 결론에 도달했습니다. 그러나 우리의 일상 업무에서 그것들은 우리를 제한적으로 돕습니다. 그렇다면 그러한 작업이 우리에게 닥쳤을 때 어떻게 진행합니까?

테스트를 격리 유지

테스트 사례와 구조를 계획할 때 항상 다른 테스트와 격리된 상태로 유지하여 독립적이거나 임의의 순서로 실행할 수 있도록 합니다. 가장 중요한 단계는 테스트 사이에 새로 설치를 복원하는 것 입니다. 또한 테스트하려는 워크플로만 테스트하고 테스트 자체에 대해서만 모의 데이터를 생성합니다. 이 바로 가기의 또 다른 장점은 테스트 성능을 향상시킬 수 있다는 것입니다. 이러한 사항을 따르면 다른 테스트의 부작용이나 남은 데이터가 방해가 되지 않습니다.

아래 예는 전자 상거래 플랫폼의 UI 테스트에서 가져온 것으로 상점의 상점 첫 화면에서 고객의 로그인을 처리합니다. (테스트는 Cypress 프레임워크를 사용하여 JavaScript로 작성되었습니다.)

 // File: customer-login.spec.js let customer = {}; beforeEach(() => { // Set application to clean state cy.setInitialState() .then(() => { // Create test data for the test specifically return cy.setFixture('customer'); }) }):

첫 번째 단계는 응용 프로그램을 새로 설치로 재설정하는 것입니다. 재설정이 모든 경우에 실행되도록 하기 위해 beforeEach 수명 주기 후크의 첫 번째 단계로 수행됩니다. 그런 다음 테스트를 위해 특별히 테스트 데이터가 생성됩니다. 이 테스트 케이스의 경우 사용자 지정 명령을 통해 고객이 생성됩니다. 그런 다음 테스트하려는 하나의 워크플로인 고객 로그인부터 시작할 수 있습니다.

테스트 구조 추가 최적화

테스트 구조를 보다 안정적으로 만들기 위해 몇 가지 다른 작은 조정을 할 수 있습니다. 첫 번째는 매우 간단합니다. 더 작은 테스트부터 시작하십시오. 이전에 말했듯이 테스트에서 더 많이 할수록 더 많이 잘못될 수 있습니다. 테스트를 가능한 한 단순하게 유지 하고 각 테스트에서 많은 논리를 피하십시오.

데이터의 순서를 가정하지 않는 것과 관련하여(예: UI 테스트에서 목록 의 항목 순서를 처리할 때) 어떤 순서와도 독립적으로 작동하도록 테스트를 설계할 수 있습니다. 정보가 있는 그리드의 예를 다시 가져오기 위해 의사 선택자 또는 순서에 대한 의존성이 강한 다른 CSS를 사용하지 않습니다. nth-child(3) 선택자 대신에 텍스트나 순서가 중요하지 않은 다른 것들을 사용할 수 있습니다. 예를 들어, "이 테이블에서 이 하나의 텍스트 문자열이 있는 요소를 찾아주세요"와 같은 어설션을 사용할 수 있습니다.

기다리다! 테스트 재시도가 가끔 괜찮습니까?

테스트를 재시도하는 것은 논란의 여지가 있는 주제이며 당연히 그렇습니다. 테스트가 성공할 때까지 맹목적으로 재시도한다면 나는 여전히 그것을 안티패턴으로 생각한다. 그러나 중요한 예외가 있습니다. 오류를 제어할 수 없는 경우 재시도는 최후의 수단이 될 수 있습니다(예: 외부 종속성에서 오류 제외). 이 경우 오류의 원인에 영향을 줄 수 없습니다. 그러나 이 작업을 수행할 때 각별히 주의하십시오. 테스트를 다시 시도할 때 벗겨짐을 눈치채지 말고 알림을 사용 하여 테스트를 건너뛸 때 알려줍니다.

다음 예는 GitLab과 함께 CI에서 사용한 예입니다. 다른 환경에서는 재시도를 달성하기 위한 구문이 다를 수 있지만 다음과 같이 맛을 볼 수 있습니다.

 test: script: rspec retry: max: 2 when: runner_system_failure

이 예에서는 작업이 실패할 경우 수행해야 하는 재시도 횟수를 구성하고 있습니다. 흥미로운 점은 러너 시스템에 오류가 있는 경우(예: 작업 설정 실패) 재시도할 수 있다는 것입니다. 도커 설정에 문제가 있는 경우에만 작업 을 다시 시도하도록 선택 합니다.

이것은 트리거될 때 전체 작업을 재시도합니다. 결함이 있는 테스트만 재시도하려면 테스트 프레임워크에서 이를 지원하는 기능을 찾아야 합니다. 다음은 버전 5 이후 단일 테스트의 재시도를 지원하는 Cypress의 예입니다.

 { "retries": { // Configure retry attempts for 'cypress run` "runMode": 2, // Configure retry attempts for 'cypress open` "openMode": 2, } }

Cypress의 구성 파일인 cypress.json 에서 테스트 재시도를 활성화할 수 있습니다. 여기에서 테스트 실행기 및 헤드리스 모드에서 재시도를 정의할 수 있습니다.

동적 대기 시간 사용

이 점은 모든 종류의 테스트, 특히 UI 테스트에서 중요합니다. 나는 이것을 충분히 강조할 수 없습니다. 고정된 대기 시간을 사용하지 마십시오 . 적어도 아주 좋은 이유 없이는 아닙니다. 그렇게 한다면 가능한 결과를 고려하십시오. 가장 좋은 경우에는 너무 긴 대기 시간을 선택하여 테스트 스위트를 필요한 것보다 느리게 만듭니다. 최악의 경우에는 충분히 기다리지 않고 애플리케이션이 아직 준비되지 않았기 때문에 테스트가 진행되지 않아 테스트가 불안정한 방식으로 실패하게 됩니다. 내 경험상 이것이 비정상적 테스트의 가장 흔한 원인입니다.

대신 동적 대기 시간을 사용하십시오. 이를 수행하는 방법은 여러 가지가 있지만 Cypress는 특히 이를 잘 처리합니다.

모든 Cypress 명령은 암시적 대기 방법을 소유합니다. 명령이 적용되는 요소가 지정된 시간 동안 DOM에 존재하는지 여부를 이미 확인합니다. 이는 Cypress의 재시도 가능성을 가리킵니다. 그러나 존재 여부만 확인 하고 그 이상은 확인하지 않습니다. 따라서 한 단계 더 나아가 실제 사용자도 볼 수 있는 웹 사이트 또는 애플리케이션 UI의 변경 사항(예: UI 자체 또는 애니메이션의 변경 사항)을 기다리는 것이 좋습니다.

Cypress의 테스트 로그에 있는 고정 대기 시간
Cypress의 테스트 로그에 있는 고정 대기 시간입니다. (큰 미리보기)

이 예에서는 선택기 .offcanvas 와 함께 요소에 대한 명시적 대기 시간을 사용합니다. 테스트는 다음과 같이 구성할 수 있는 지정된 시간 초과까지 요소가 표시되는 경우에만 진행됩니다.

 // Wait for changes in UI (until element is visible) cy.get(#element).should('be.visible');

동적 대기를 위한 Cypress의 또 다른 깔끔한 가능성은 네트워크 기능입니다. 예, 요청이 발생하고 응답 결과가 나올 때까지 기다릴 수 있습니다. 나는 이런 종류의 기다림을 특히 자주 사용합니다. 아래 예에서는 기다릴 요청을 정의하고 wait 명령을 사용하여 응답을 기다리고 상태 코드를 어설션합니다.

 // File: checkout-info.spec.js // Define request to wait for cy.intercept({ url: '/widgets/customer/info', method: 'GET' }).as('checkoutAvailable'); // Imagine other test steps here... // Assert the response's status code of the request cy.wait('@checkoutAvailable').its('response.statusCode') .should('equal', 200);

이렇게 하면 애플리케이션이 필요로 하는 만큼 정확히 기다릴 수 있어 테스트를 보다 안정적으로 만들고 리소스 누출 또는 기타 환경 문제로 인한 취약성을 줄일 수 있습니다.

불안정한 테스트 디버깅

이제 우리는 설계상 비정상적 테스트를 방지하는 방법을 알고 있습니다. 그러나 이미 불안정한 테스트를 처리하고 있다면 어떻게 될까요? 어떻게 제거할 수 있습니까?

디버깅할 때 루프에 결함이 있는 테스트를 넣는 것이 취약성을 발견하는 데 많은 도움이 되었습니다. 예를 들어 테스트를 50번 실행하고 매번 통과하면 테스트가 안정적이라는 것을 더 확신할 수 있습니다. 그렇지 않은 경우 최소한 비정상적 테스트에 대해 더 많은 통찰력을 얻을 수 있습니다.

 // Use in build Lodash to repeat the test 100 times Cypress._.times(100, (k) => { it(`typing hello ${k + 1} / 100`, () => { // Write your test steps in here }) })

이 불안정한 테스트에 대해 더 많은 통찰력을 얻는 것은 CI에서 특히 어렵습니다. 도움을 받으려면 테스트 프레임워크가 빌드에 대한 추가 정보를 얻을 수 있는지 확인하세요. 프론트 엔드 테스트의 경우 일반적으로 테스트에서 console.log 를 사용할 수 있습니다.

 it('should be a Vue.JS component', () => { // Mock component by a method defined before const wrapper = createWrapper(); // Print out the component's html console.log(wrapper.html()); expect(wrapper.isVueInstance()).toBe(true); })

이 예제는 테스트 중인 구성 요소의 HTML 출력을 가져오기 위해 console.log 를 사용하는 Jest 단위 테스트에서 가져온 것입니다. Cypress의 테스트 러너에서 이 로깅 가능성을 사용하면 선택한 개발자 도구에서 출력을 검사 할 수도 있습니다. 또한 CI의 Cypress의 경우 플러그인을 사용하여 CI 로그에서 이 출력을 검사할 수 있습니다.

로깅 지원을 받으려면 항상 테스트 프레임워크의 기능을 살펴보십시오. UI 테스트에서 대부분의 프레임워크는 스크린샷 기능 을 제공합니다. 적어도 실패 시 스크린샷이 자동으로 찍힐 것입니다. 일부 프레임워크는 비디오 녹화 를 제공하기도 합니다. 이는 테스트에서 일어나는 일에 대한 통찰력을 얻는 데 큰 도움이 될 수 있습니다.

플레이크니스 악몽과 싸워라!

처음부터 방지하거나 발생하는 즉시 디버깅 및 수정하여 불안정한 테스트를 지속적으로 찾는 것이 중요합니다. 응용 프로그램의 문제를 암시할 수 있으므로 심각하게 받아들여야 합니다.

적기 발견하기

물론 처음부터 비정상적 테스트를 방지하는 것이 가장 좋습니다. 빠르게 요약하자면 다음과 같은 몇 가지 위험 신호가 있습니다.

  • 테스트는 크고 많은 논리를 포함합니다.
  • 테스트는 많은 코드를 다룹니다(예: UI 테스트에서).
  • 테스트는 고정 대기 시간을 사용합니다.
  • 테스트는 이전 테스트에 따라 다릅니다.
  • 테스트는 ID, 시간 또는 데모 데이터, 특히 무작위로 생성된 데이터의 사용과 같이 100% 예측할 수 없는 데이터를 주장합니다.

이 기사의 포인터와 전략 을 염두에 두면 불안정한 테스트가 발생하기 전에 예방할 수 있습니다. 그리고 그들이 오면 디버그하고 수정하는 방법을 알게 될 것입니다.

이러한 단계는 테스트 제품군에 대한 자신감을 회복하는 데 정말 도움이 되었습니다. 우리의 테스트 스위트는 현재 안정적인 것 같습니다. 미래에 문제가 발생할 수 있습니다. 100% 완벽한 것은 없습니다. 이 지식과 ​​이러한 전략은 내가 그것들을 다루는 데 도움이 될 것입니다. 따라서 나는 그 들쭉날쭉한 테스트 악몽과 맞서 싸울 수 있는 내 능력에 자신감을 갖게 될 것입니다.

각질에 대한 여러분의 고통과 걱정을 조금이나마 덜어드릴 수 있기를 바랍니다!

추가 읽기

이 주제에 대해 더 자세히 알고 싶다면 다음과 같은 유용한 리소스와 기사를 참조하세요. 많은 도움이 되었습니다.

  • "플레이크"에 대한 기사, Cypress.io
  • "테스트를 다시 시도하는 것은 실제로 좋은 일입니다(접근 방식이 올바른 경우)", Filip Hric, Cypress.io
  • Spotify R&D Engineering의 Jason Palmer, "테스트 취약성: 취약한 테스트 식별 및 처리 방법"
  • "Google의 비정상적인 테스트와 이를 완화하는 방법", John Micco, Google 테스팅 블로그