{
    "componentChunkName": "component---src-templates-blog-post-js",
    "path": "/21-10-07-test-and-spec-again/",
    "result": {"data":{"site":{"siteMetadata":{"title":"irrationnelle","author":"irrationnelle","siteUrl":"https://dev.rase.blog","comment":{"disqusShortName":"","utterances":"irrationnelle/devlog"},"sponsor":{"buyMeACoffeeId":""}}},"markdownRemark":{"id":"8e8c569e-a7d6-5436-a5ab-83c35b93e3b1","excerpt":"다시, 테스트 코드는 왜 스펙인가 약 반년 전에 이런 글 을 작성한 적이 있다. 이번에도 다시 테스트 코드와 스펙에 대한 이야기를 하려고 한다. 저번 이야기와 비슷한 이야기지만, 더 중요한 이야기가 될 것 같다. iOS 에는 단축어라는 기능이 있다. 특정 상황에서 iOS 가 사용자 대신 미리하기로 했던 시나리오를 수행하는 기능이다. 예를 들어 음악앱을 사용할 때, 음악앱 자체는 사용자가 클릭하고 음악을 고르기 전까지는 절대로 스스로 작동하지 않는다. 하지만 단축어를 사용하면, 오전…","html":"<h2 id=\"다시-테스트-코드는-왜-스펙인가\" style=\"position:relative;\"><a href=\"#%EB%8B%A4%EC%8B%9C-%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>다시, 테스트 코드는 왜 스펙인가</h2>\n<p>약 반년 전에 <a href=\"https://dev.rase.blog/21-02-03-test-spec-why-fail/\">이런 글</a> 을 작성한 적이 있다.</p>\n<p>이번에도 다시 테스트 코드와 스펙에 대한 이야기를 하려고 한다. 저번 이야기와 비슷한 이야기지만, 더 중요한 이야기가 될 것 같다.</p>\n<hr>\n<p>iOS 에는 단축어라는 기능이 있다.</p>\n<p>특정 상황에서 iOS 가 사용자 대신 미리하기로 했던 시나리오를 수행하는 기능이다.</p>\n<p>예를 들어 음악앱을 사용할 때, 음악앱 자체는 사용자가 클릭하고 음악을 고르기 전까지는 절대로 스스로 작동하지 않는다. 하지만 단축어를 사용하면, 오전 8시에 음악앱이 스스로 재즈 음악을 재생하도록 할 수 있다.</p>\n<p>테스트 코드는 위의 단축어 개념과 유사하다.</p>\n<p>테스트 코드의 대상은 사용자 interaction 이 있기 전까지는 작동하지 않는다. 이 때 테스트 러너의 도움을 통해 환경을 구축하고 사용자 interaction 을 상정하는 시나리오를 테스트 코드로 작성하면 테스트 코드의 대상은 무언가 변화를 일으키고 그 결과를 보여준다. 단축어와 차이가 있다면 자동화 테스트는 그 결과가 우리의 기대값과 일치하는지 확인(assertion)하는 과정을 포함한다. 때로는 실제 시각과 상관없이 오전 8시라고 속일 수도(test double) 있다.</p>\n<hr>\n<p>다시 단축어로 돌아가보자.</p>\n<p>이번에는 단축어 대신 실제로 오전 8시에 스스로 재즈 음악을 재생하는 어플리케이션을 제작한다고 하자.</p>\n<p>어플리케이션은 오전 8시 외에는 음악을 재생하면 안 된다.</p>\n<p>그런데 만약 오전 7시에 음악을 재생한다면, 그 앱은 스펙(명세)을 어긴 것이다.</p>\n<p>예정보다 1시간 일찍 일어나서 분노한 사용자는 가차없이 어플리케이션을 지울 것이다.</p>\n<hr>\n<p>이해를 쉽게 하기 위해 단축어와 오전 8시에 자동으로 재생하는 음악 앱의 이야기를 했지만, 예시란 사실 오해의 여지를 남기기도 한다.</p>\n<p>그래서 오전 8시의 자동재생은 이제 머리속에서 지우자. 하루에 단 한 번만 통과하는 테스트를 작성할 것이 아니라면 이 테스트 시나리오는 필연적으로 test double 을 사용한다. 또 test double 도입이 곧 변경점이기 때문에 오해의 여지가 있다.</p>\n<p>대신 일반적으로 개발할 때 자주 접하는 상황을 이야기하자.</p>\n<hr>\n<p>다음과 같은 시나리오를 상정하자.</p>\n<blockquote>\n<p>어떤 버튼을 클릭했을 때 사용자가 로그인 상태라면 회원정보 메뉴를 보여준다. 사용자가 로그아웃 상태라면 로그인하기 메뉴를 보여준다.</p>\n</blockquote>\n<p>이 버튼은 아주 간결한 시나리오를 수행한다. 사용자의 상태는 로그인을 했는지 안 했는지만을 판단한다.</p>\n<p>이 시나리오에 테스트 코드를 먼저 작성한다. 그러면 실제 코드를 작성하지 않아 당연히 테스트가 실패한다. 테스트 성공을 위해 실제 코드를 작성한다. 이 실제 코드는 테스트 코드를 만족시키는 코드가 된다.</p>\n<blockquote>\n<p>만약 여기서 사용자가 로그인 상태이지만 이메일 인증 등의 과정을 거치지 않았다면?</p>\n</blockquote>\n<blockquote>\n<p>만약 사용자가 로그인 상태이지만 발급받은 토큰이 만료되었다면?</p>\n</blockquote>\n<p>위와 같은 의문은 상용화 서비스에서 응당 고려해야 하는 부분이다. 그래서 버튼을 클릭했을 때 이메일 인증과 토큰 만료 여부를 확인하는 과정을 실제 코드에 추가했다고 가정하자.</p>\n<p>이 경우, 실제 코드는 테스트 시나리오가 다루지 않는 군더더기 코드를 담는다. 테스트 코드 입장에선 다음 두 가지가 모두 군더더기이다.</p>\n<ul>\n<li>\n<p>실제 코드가 토큰 만료를 확인한다.</p>\n</li>\n<li>\n<p>실제 코드가 길이 1000짜리 배열의 각 요소들을 제곱한 뒤 그 결과를 모두 합하고, 그 값에 0을 곱한 후, 마지막으로 그 값이 1보다 큰지 비교하는 조건문을 만들어서, 그 조건문 내부에서 logger 를 호출한다.</p>\n</li>\n</ul>\n<p>왜 군더더기인가? 테스트 코드가 요구하는 시나리오에는 위 두가지가 하나같이 필요없기 때문이다.</p>\n<hr>\n<p>그래서 뒤늦게 부랴부랴 토큰 만료를 확인하는 테스트를 추가하면, 테스트 코드는 그 시나리오를 다루는 것이 될 수도 있다.</p>\n<p>잠정적으로 이야기하는 것은 다음 두 가지 이유에서이다.</p>\n<ul>\n<li>\n<p>테스트 코드를 언제나 성공하는 테스트로 만들었을 경우 그 시나리오를 고려하지 않는 테스트와 동일하다.</p>\n</li>\n<li>\n<p>방금 작성한 테스트가 충족하는 시나리오 외의 또다른 시나리오를 실제 코드가 내포할 수 있다.</p>\n</li>\n</ul>\n<p>전자는 몇번의 시행착오 및 세심한 주의력으로 어찌저찌 해결할 수 있다. 실제 코드를 의도적으로 오염시킨다거나 하는 방법으로 확인할 수도 있다. 물론 비용이 드는 방법이지만, 어쨌든 해결할 수 있을 것이다.</p>\n<p>문제는 후자이다.  이미 작성한 코드가 토큰 만료만 다룬다고 생각했는데 알고보니 앱 초기화까지 포함한 경우라면?</p>\n<p>이 경우, 테스트 코드 입장에서는 실제 코드는 버그를 가지고 있는 것이다. 앱 초기화가 기획상에서 요구한 기능이라 하더라도. 그 유명한 ‘버그가 아니라 기능입니다’ 의 탄생이다.</p>\n<hr>\n<p>테스트 코드는 스펙일 수도 있다. 테스트 코드가 실제 코드가 지향하는 시나리오의 일부를 담고 있기 때문이다.</p>\n<p>하지만 TDD 의 경우, 테스트 코드는 스펙 그 자체이다. 실제 코드는 기획서나 사용자 설문조사의 내용을 반영하지 않는다. 실제 코드는 그저 테스트 코드의 시나리오를 만족시키고 테스트 코드가 통과하는 것을 기대한다.</p>","frontmatter":{"title":"다시, 테스트 코드는 왜 스펙인가","date":"October 07, 2021"}}},"pageContext":{"slug":"/21-10-07-test-and-spec-again/","previous":{"fields":{"slug":"/21-08-29-firebase-auth-sign-in-with-google/"},"frontmatter":{"title":"firebase auth 이용하여 google 로그인 구현","category":"firebase","draft":false}},"next":{"fields":{"slug":"/21-10-07-context-and-state-management/"},"frontmatter":{"title":"React 에서 Context API 와 상태관리","category":"react","draft":false}}}},
    "staticQueryHashes": ["3128451518","3474900066"]}