본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[Effective Unit Testing] Chap1. 좋은 테스트의 약속

by 돼지왕 왕돼지 2019. 2. 26.
반응형

[Effective Unit Testing] Chap1. 좋은 테스트의 약속


auto unit test, bdd, behavior driven developmenet, diminishing return, effective unit testing, tdd, [Effective Unit Testing] Chap1. 좋은 테스트의 약속, 검증 수단, 디버깅 시간, 리펙토링, 사용설명서, 설계 보조 수단, 설계 잠재력 곡선, 설계 코딩 테스트 순서, 수확 체감, 요구사항, 유지보수, 인수인계, 자동화 단위 테스트, 좋은 설계, 좋은 테스트의 약속, 테스트 가독성, 테스트 리펙토링, 테스트 생산성, 테스트 선행 방식, 테스트 설계, 테스트 설계 지향, 테스트 신뢰성, 테스트 안정성, 테스트 작성 테스트 통과 리펙토링, 테스트 주도 개발, 테스트 커버리지, 테스트 코딩 설계 순서, 테스트의 가치, 테스트의 목적, 품질 고지, 피드백 주기, 행위 주도 개발

-

좋은 설계임을 증명하려거든 자동화된 테스트를 만들어보라!



-

테스트에 대한 인식 전환이 필요하다.

테스트란 단순한 기능 검증 수단만이 아닌 요구사항을 명시한 문장이요, 모듈과 API 설계 수단이며, 사용설명서이자, 최고의 인수인계/유지보수 자료이기까지 하다.

개발자의 설계역량 면에서 보면, 디자인 패턴에만 의지하기보다 테스트하기 쉬운 설계를 추구하는 쪽이 훨씬 탄탄한 기본기와 응용력을 길러줄 것이라고 감히 단언할 수 있다.





1.1. 더 좋은 테스트를 작성하기 위한 현황 점검

-

테스트 선행 방식에서는 자동화된 테스트를 단순한 오류 예방 목적으로뿐 아니라, 코딩 전에 그 코드에 기대하는 동작을 정의하는 설계 보조 수단으로까지 활용한다.

구현까지 다 끝나야 검증을 시작하는 것이 아니라 애초에 설계부터 검증하고 들어가는 것이다.





1.2. 테스트의 가치

-

테스트는 실수를 바로잡아준다.



-

100% 코드 커버리지 달성이 중요한 게 아니다.

테스트의 가치는 테스트가 확인하지 못한 코드가 어떤 것인가와 테스트가 프로그래밍 실수를 얼마나 정확하게 잡아내는가에 좌우된다.

100% 달성했다고 해서 결함이 없다고 보장해주는 건 아니다.

앱 동작이 올바른가와는 상관없이, 그저 모든 코드를 한 번씩은 실행해보았다는 것만을 보장할 뿐이다.



-

테스트는 실사용에 적합한 설계를 끌어내준다.

테스트가 단순한 품질 보증이나 실수 재발 방지 수단만은 아니다.

테스트는 분명 코드를 설계하는 한 방식이기도 하다.



-

테스트는 원하는 동작을 명확히 알려주어 군더더기(gold-plating)을 없애준다.



-

테스트 추종 개발자들은 처음에는 시간을 좀먹는 부끄러운 실수를 예방할 생각으로 자동화된 단위 테스트를 작성하기 시작한다.

그리고 시간이 지날수록 안전장치로써의 역할은 전체 그림의 일부일 뿐임을 깨닫게 된다.

오히려 테스트를 코딩에 접목하면서 경험하는 사고과정이 더 가치 있을 것이다.



-

자동화된 단위 테스트는 개발자가 직접 작성해야 한다는 인식은 이미 널리 퍼져있지만, 어떤 테스트를 얼마나 많이 작성해야 하는가에 대한 인식은 여전히 부족하다.



-

테스트를 작성해야 한다는 데에는 누구나 동의하지만, 커버리지가 100%에 근접해질수록 테스트를 더 작성해야 하는가에 대해서는 확신이 줄어든다.

작성할 테스트를 거의 다 작성했다면 나머지 코드에서 문제가 발견될 가능성은 낮아지기 때문이다.

이것이 바로 수확 체감(diminishing return)이다.

그러나!! 테스트를 작성해서 얻게 되는 가장 큰 수확은 테스트 자체가 아니다. 작성 과정에서 얻는 깨달음이다.

테스트를 설계 도구로 인식하는 순간 품질 고지를 뛰어넘어 설계 고지에 도달하는 길이 열리게 된다.




1.2.1. 생산성에 영향을 주는 요소

-

테스트 코드는 제품 코드보다 간결한 게 보통이다.

그렇다 해서 테스트 코드를 허투루 작성하고 문제를 심어 놓으면, 나중에 분명 발목 잡힐 날이 올 거다.

중복도 많고 쓸데없이 복잡한 테스트 코드는 생산성을 떨어뜨리고 테스트의 긍정적 효과마저 앗아간다는 걸 명심하자.



-

생산성에 직접 영향을 주는 피드백 주기와 디버깅 시간에 주목해보자.

경험상 이 두 가지가 가장 유력한 야근의 요정이다.

실수하자마자 곧바로 알아차릴 수만 있다면 지루한 디버깅을 상당히 피할 수 있지만, 피드백 주기가 길어질수록 디버깅 시간도 길어지게 마련이다.



-

"테스트 실행 속도"는 변경사항을 검증하고 확인하기 위해 기다리는 시간에 직결딘다.

“가독성"이 떨어지면 자연스럽게 분석이 더뎌지고 디버거를 사용해야 할 상황까지 만들 수 있다. 테스트 코드를 읽어봐도 무슨 말인지 이해하기 어렵다. 그러면 실수한 곳을 찾기 어려워 더 많은 결함이 만들어지고, 늘어난 결함은 디버깅 시간 증가로 이어진다.

“테스트 결과의 정확성”도 발견하지 못하고 놓치는 결함의 수에 많은 영향을 준다. 실수로 결함을 만들어도 테스트 스위트가 찾아줄 거라며 믿고 의지하고 싶다면 정확성이라도 반드시 보장되어야 한다. “신뢰성” 과 “안정성”이 바로 이 테스트 정확성과 직접 연관되어 있다. 테스트 결과를 믿고 싶다면 테스트가 약속한 것을 확실히 잡아내고 몇 번을 수행해도 항시 같은 결과가 나오도록 만들어야 한다.







1.2.2. 설계 잠재력 곡선

-

제품 코드의 가장 대표적인 시나리오와 구조상 가장 치명적인 부분을 먼저 검사했다.

테스트 품질도 상급이고 철저한 리펙토링으로 중복까지 말끔히 제거해서 가볍고 유지보수도 쉬워졌다.

나머지 주요 기능을 모두 검사하고 getter/setter 등의 사소한 기능만 남았다.

테스트 커버리지가 높은 것은 당연하다.

이 상태에서 마지막 남은 사소한 테스트는 작성해봤자 큰 가치가 없다.

이는 수확 체감에 다다랐다는 신호로, 단지 테스트만 작성해서 얻을 수 있는 가치의 한계점에 도달한 것이다.

이곳이 바로 일반적인 방식으로 도달할 수 있는 최고점인 품질 고지다.



-

한계를 뛰어넘어 한 차원 높은 생산성을 맛보고자 한다면 환골탈태를 거쳐야 한다.

지금까지 가지고 있던 테스트에 관한 사고의 틀을 깨야만 한다.

실수가 반복되는 것을 예방한다는, 방어적이고 검증 지향적인 가치가 아닌, 더 창조적이고 설계 지향적인 가치가 그것이다.



-

테스트의 잠재 가치를 전부 끌어내고 두 고지를 모두 정복하려면 다음처럼 하면 된다.

1. 테스트 코드도 제품 코드를 다루듯 하라. 믿고 의지할 수 있을 만큼 철처하게 리펙토링하고 높은 품질을 유지하라.

2. 테스트를 제품 코드가 목적과 쓰임새에 적합한 구조가 되게끔 이끌어주는 설계 수단으로 활용하라.





1.3. 설계 수단으로써의 테스트

-

프로그래머가 작성한 자동화 테스트는 전통적으로 크게 두 가지 목적을 위한 품질보증 수단이었다.

첫째는 코드를 작성하는 즉시 정확하게 구현했는지 검사하는 것이고, 둘째는 그 후에 코드베이스가 커져도 계속 잘 동작하는지 지속해서 확인하는 것이다.



-

자동화된 테스트를 설계 수단으로 이용하기 시작하면 모든 것이 뒤바뀐다.

테스트를 코드 설계용으로 사용하면 익숙했던 설계, 코딩, 테스트의 순서가 테스트, 코딩, 설계로 바뀐다.

테스트가 코딩보다 선행되고 설계로 마무리된다.

마지막의 설계 단계는 리펙토링이라는 이름으로 더 유명하다.




1.3.1. 테스트 주도 개발

-

테스트 주도 개발에서는 실패하는 테스트 작성하기, 테스트 통과하기, 중복을 줄이고 의도를 명확하게 하기 위한 코드 리펙토링을 반복한다.



-

테스트를 먼저 작성하면 소위 테스트로 설계한 제품 코드가 만들어진다. 이의 긍정적 효과는..

    '사용 가능한 코드가 만들어진다’ 즉, 제품 코드의 설계와 API 가 활용 시나리오에 적합한 모습으로 거듭난다.

    '코드가 가벼워진다’ 실제로 활용할 시나리오에서 요구하는 기능만을 담게 된다.




1.3.2. 행위 주도 개발

-

댄 노스라는 런던의 컨설턴트는 TDD 에서 말하는 테스트라는 용어가 사람들을 잘못된 길로 인도함을 깨달았다.

그래서 자신만의 TDD 방식을 만들고 행위 주도 개발(BDD, Behavior-driven development) 이라는 이름을 붙였다.

테스트의 이름을 짓는 건 정말 쉬워졌다. 검사하려는 행위를 기술하는 문장이면 된다.

테스트할 범위를 정하는 문제의 답도 간단하다.

답은 한 문장으로 기술할 수 있는 만큼의 행위다.





1.4. 요약

-

프로그래머가 마구잡이식 코딩에서 벗어난 지 한참이 지났다.

코드 전반을 보호해주는 자동화된 테스트 스위트(Suite)의 가치를 더는 부정할 수 없다.



-

1장에서는 두 개의 고지가 무엇인지 배웠다.

이미 높은 커버리지를 달성하여 테스트를 더 만들어봐야 얻을 게 거의 없는 지점이 첫 번째 고지다.

하지만 우리는 더 높이 오를 수 있다.

테스트 코드의 품질(& 설계)까지 신경 쓴다면 첫 번째 고지를 박차고 올라 더 위로 올라설 수 있다.

전자가 테스트를 갖춰야 하는 이유라면 후자는 좋은 테스트를 갖춰야 하는 이유다.





반응형

댓글