{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/21-02-03-test-spec-why-fail/",
    "result": {"data":{"site":{"siteMetadata":{"title":"irrationnelle","author":"irrationnelle","siteUrl":"https://dev.rase.blog","comment":{"disqusShortName":"","utterances":"irrationnelle/devlog"},"sponsor":{"buyMeACoffeeId":""}}},"markdownRemark":{"id":"11f39782-babb-5190-aa76-e92b2fd152e8","excerpt":"테스트 코드는 왜 스펙인가 cypress 가 앞으로도 다중 접속을 허용할 계획이 없다고 하여 e2e 테스트를 playwright 와 jest 조합으로 변경했다. cypress 에서 익숙했던 selector 설정에서 다시 playwright 에서 지정한 selector 탐색 방법을 사용하다 보니 로컬 테스트를 통과시키는 과정도 꽤 험난했다. 이 과정에서 playwright 키워드로 검색 결과가 안 나오면 puppeteer 에서 어떻게 selector 를 인식하거나 element attribute…","html":"<h1 id=\"테스트-코드는-왜-스펙인가\" style=\"position:relative;\"><a href=\"#%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%99%9C-%EC%8A%A4%ED%8E%99%EC%9D%B8%EA%B0%80\" aria-label=\"테스트 코드는 왜 스펙인가 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>테스트 코드는 왜 스펙인가</h1>\n<p>cypress 가 앞으로도 다중 접속을 허용할 계획이 없다고 하여 e2e 테스트를 playwright 와 jest 조합으로 변경했다.</p>\n<p>cypress 에서 익숙했던 selector 설정에서 다시 playwright 에서 지정한 selector 탐색 방법을 사용하다 보니 로컬 테스트를 통과시키는 과정도 꽤 험난했다.</p>\n<p>이 과정에서 playwright 키워드로 검색 결과가 안 나오면 puppeteer 에서 어떻게 selector 를 인식하거나 element attribute 등을 다루는지 찾아보면 된다는 나름의 노하우도 얻었다. 최근에는 playwright  에서  <code class=\"language-text\">page.isDisabled(‘selector’)</code>  와 같은 나름 세련된 메소드를 제공하긴 한다.</p>\n<p>어찌저찌 힘겹게 로컬에서 테스트를 성공시키면 그때부터 문제인게, 답도 없는 기도 시간에 들어가야 한다.</p>\n<p>즉 로컬에서는 문제없이 통과하는 테스트가 CI/CD 단계에서는 실패하는 경우가 생긴다는 것인데, 일단 CICD 단계까지 거쳐야 하니 디버깅에 쏟는 시간이 배로 불어난다.</p>\n<p>이 때 주로 접하는 에러 메시지는 timeout 시간을 초과했다는 메시지를 주로 본다.</p>\n<p>그리고 이어서 따라오는 메시지는 테스트 시나리오에 따라가기 위해 지정한 element 에 지정한 이벤트가 발생하길 기다렸지만 끝내 timeout 때문에 예외를 던졌다고 한다.</p>\n<p>여기서  지정한 이벤트란 다음과 같은 것들이다. 버튼 클릭, element 사라지기, 체크박스에 체크하기 등등.</p>\n<p>파일을 업로드 하는 과정을 예로 들겠다.</p>\n<ol>\n<li>fixture 파일을 업로드한다.</li>\n<li>업로드 대상을 선택하기 위해 미리보기 이미지가 나타난다.</li>\n<li>미리보기 이미지는 개별 선택이 가능하고 전체 선택을 위한 체크 박스가 나타난다.</li>\n<li>미리보기 이미지를 선택하지 않으면 업로드 확인 버튼은 disabled 상태이다.</li>\n<li>전체 선택을 위해 체크박스를 체크한다</li>\n<li>업로드 확인 버튼을 눌러 업로드한다.</li>\n<li>원하는 파일을 업로드 했는지 확인한다.</li>\n</ol>\n<p>이게 업로드 시나리오라고 생각했고 이 시나리오대로 테스트를 작성했을 뿐인데 CI/CD 에서 실패하는 것이다.</p>\n<p>그럼 보통 이렇게 생각을 한다.</p>\n<blockquote>\n<p>CI / CD 서버가 구려서 시나리오대로 진행하는 데에 좀 더 시간이 걸린다</p>\n</blockquote>\n<p>즉 입장을 하는데에도 로컬보다 더 시간이 걸리고, 파일 업로드 과정 로컬에서조차 시간이 어느 정도 걸리는 작업이기 때문에 CI/CD 서버에서는 더 넉넉한 timeout 을 주어야 한다고 생각한다.</p>\n<p>하지만 이 생각은 틀렸다.</p>\n<h2 id=\"ci--cd-에서-실패하는-테스트는-로컬에서도-실패한다고-생각해야-한다\" style=\"position:relative;\"><a href=\"#ci--cd-%EC%97%90%EC%84%9C-%EC%8B%A4%ED%8C%A8%ED%95%98%EB%8A%94-%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%8A%94-%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C%EB%8F%84-%EC%8B%A4%ED%8C%A8%ED%95%9C%EB%8B%A4%EA%B3%A0-%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC-%ED%95%9C%EB%8B%A4\" aria-label=\"ci  cd 에서 실패하는 테스트는 로컬에서도 실패한다고 생각해야 한다 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>CI / CD 에서 실패하는 테스트는 로컬에서도 실패한다고 생각해야 한다.</h2>\n<p>위에 내가 테스트 시나리오 과정으로 작성한 것과 실제 업로드 과정에는 세부적인 부분이 달랐다.</p>\n<p>특히 테스트가 실패하는 가장 큰 원인은 바로 전체 선택을 위한 체크 박스 클릭이 문제였다.</p>\n<blockquote>\n<p>이 체크박스 클릭은 서버에 업로드를 완료하고 서버로부터 메타 정보를 무사히 받아올 때까지 disabled 상태가 되는 상태를 가지고 있었다.</p>\n</blockquote>\n<p>하지만 로컬에서 테스트할 때는 disabled 되는 상태가 너무나도 짧기 때문에 체크 박스를 클릭하려는 시점에 disabled 가 될 일이 거의 없었다. 하지만 CI/CD 서버에서는 체크박스를 클릭하기 이전에 먼저 체크박스가 disabled 상태인지 확인을 하고 disabled 라면 체크가 가능한 상태까지 기다려야만 한다.</p>\n<p>그래서 CI/CD 를 위해 여러 selector 탐색 과정에 timeout 을 길게 배정해도, 3번 단계에서 이미 테스트는 진전을 하지 않고 있기 때문에 테스트가 실패하는 것이었다.</p>\n<p>즉 위 테스트 시나리오의 3과 4 사이에 체크박스의 disabled 여부를 확인해야만 했던 것이다.</p>\n<h2 id=\"테스트-코드는-스펙이라는-말\" style=\"position:relative;\"><a href=\"#%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C%EB%8A%94-%EC%8A%A4%ED%8E%99%EC%9D%B4%EB%9D%BC%EB%8A%94-%EB%A7%90\" aria-label=\"테스트 코드는 스펙이라는 말 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>테스트 코드는 스펙이라는 말</h2>\n<p>테스트 코드가 스펙이라는 말은 굉장히 추상적이라고 생각한 적이 있다. 읽기 좋은 테스트 코드를 작성하지 못하기 때문일까, 과장 좀 많이 하면 테스트 코드를 읽는 과정이 실제 코드를 읽는 과정만큼 난해하다고 느낄 때가 있기 때문이다.</p>\n<p>하지만 이번 일을 계기로 테스트 코드는 스펙이라는 말이 조금 더 와닿았다. 아직도 모호한 면이 있지만, 코드가 A -> B -> C 의 흐름을 가지고 있다면 테스트 코드도 A -> B -> C 를 따라가야 한다. 그리고 그것은 A -> B -> C 흐름의 명세가 될 것이다.</p>\n<p>만약 테스트 코드가 A -> B -> C 의 흐름을 정확히 나타내고 있는데 테스트 코드가 실패한다면, 코드의 실제 흐름은 A -> B -> C 가 아니라 A -> C 는 아닌지, 또는 A -> B -> Z -> C 는 아닌지 확인할 필요가 있다.</p>","frontmatter":{"title":"테스트 코드는 왜 스펙인가","date":"February 03, 2021"}}},"pageContext":{"slug":"/21-02-03-test-spec-why-fail/","previous":{"fields":{"slug":"/21-02-03-promise-call/"},"frontmatter":{"title":"Promise 실행과 평가 시점에 대하여","category":"Dev","draft":false}},"next":{"fields":{"slug":"/21-03-20-magic-number/"},"frontmatter":{"title":"매직 넘버를 지양해야 하는 이유","category":"Dev","draft":false}}}},
    "staticQueryHashes": ["3128451518","3474900066"]}