개발자 99% 커뮤니티에서 수다 떨어요!
오늘 TIL 3줄 요약
깨끗한 테스트코드를 만들려면 가독성이 중요하다.
자신이 만든 코드는 간결하고 표현력이 풍부한 코드로 리팩터링 해야한다.
테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화하므로 지속적으로 깨끗하게 관리하자.
TIL (Today I Learned) 날짜
2022. 03. 06
오늘 읽은 범위
8장 경계, 9장 단위테스트
책에서 기억하고 싶은 내용을 써보세요.
경계
곧바로 우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히면 어떨까? 짐 뉴커크는 이를 학습 테스트라 부른다.
학습 테스트는 프로그램에서 사용하려는 방식대로 외부 API를 호출한다. 통제된 환경에서 API를 제대로 이해하는지를 확인하는 셈이다. 학습 테스트는 API 를 사용하려는 목적에 초점을 맞춘다.
학습 테스트에 드는 비용은 없다. 어쨌든 API를 배워야 하므로……. 오히려 필요한 지식만 확보하는 손쉬운 방법이다. 학습 테스트는 이해도를 높여주는 정확한 실험이다.
학습 테스트는 공짜 이상이다. 투자하는 노력보다 얻는 성과가 더 크다. 패키지 새 버전이 나온다면 학습 테스트를 돌려 차이가 있는지 확인한다.
경계에 위치하는 코드는 깔끔히 분리한다. 또한 기대치를 정의하는 테스트 케이스도 작성한다. 이쪽 코드에서 외부 패키지를 세세하게 알아야 할 필요가 없다. 통제가 불가능한 외부 패키지에 의존하는 대신 통제가 가능한 우리 코드에 의존하는 편이 훨씬 좋다. 자칫하면 오히려 외부 코드에 휘둘리고 만다.
외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자.
단위테스트
Professionalism and Test-Driven Development
첫째 법칙: 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
둘째 법칙: 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
셋째 법칙: 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
문제는 실제 코드가 진화하면 테스트 코드도 변해야 한다는 데 있다. 그런데 테스트 코드가 지저분할 수록 변경하기 어려워진다. 테스트 코드가 복잡할수록 실제 코드를 짜는 시간보다 테스트 케이스를 추가하는 시간이 더 걸리기 십상이다. 실제 코드를 변경해 기존 테스트 케이스가 실패하기 시작하면, 지저분한 코드로 인해, 실패하는 테스트 케이스를 점점 더 통과시키기 어려워진다. 그래서 테스트 코드는 계속해서 늘어나는 부담이 되버린다.
깨끗한 테스트 코드를 만들려면? 세 가지가 필요하다. 가독성, 가독성, 가독성.
어쩌면 가독성은 실제 코드보다 테스트 코드에 더더욱 중요하다. 테스트 코드에서 가독성을 높이려면? 여느 코드와 마찬가지다. 명료성, 단순성, 풍부한 표현력이 필요하다. 테스트 코드는 최소의 표현으로 많은 것을 나타내야 한다.
첫 부분은 테스트 자료를 만든다. 두 번째 부분은 테스트 자료를 조작하며, 세 번째 부분은 조작한 결과가 올바른지 확인 한다.
잡다하고 세세한 코드를 거의 다 없앴다는 사실에 주목한다. 테스트 코드는 본론에 돌입해 진짜 필요한 자료 유형과 함수만 사용한다. 그러므로 코드를 읽는 사람은 온갖 잡다하고 세세한 코드에 주눅들고 헷갈릴 필요 없이 코드가 수행하는 기능을 재빨리 이해한다.
숙련된 개발자라면 자기 코드를 좀 더 간결하고 표현력이 풍부한 코드로 리팩터링해야 마땅하다.
어쩌면 “테스트 함수마다 한 개념만 테스트하라”는 규칙이 더 낫겠다. 이것저것 잡다한 개념을 연속으로 테스트하는 긴 함수는 피한다.
빠르게 Fast : 테스트는 빨라야 한다. 테스트는 빨리 돌아야 한다는 말이다. 테스트가 느리면 자주 돌릴 엄두를 못 낸다. 자주 돌리지 않으면 초반에 문제를 찾아내 고치지 못한다. 코드를 마음껏 정리하지도 못한다. 결국 코드 품질이 망가지기 시작한다.
독립적으로 Independent : 각 테스트는 서로 의존하면 안 된다. 한 테스트가 다음 테스트가 실행될 환경을 준비해서는 안 된다. 각 테스트는 독립적으로 그리고 어떤 순서로 실행해도 괜찮아야 한다. 테스트가 서로에게 의존하면 하나가 실패할때 나머지도 잇달아 실패하므로 원인을 진단하기 어려워지며 후반 테스트가 찾아내야 할 결함이 숨겨진다.
반복가능하게 Repeatable : 테스트는 어떤 환경에서도 반복 가능해야 한다. 실제 환경, QA 환경, 버스를 타고 집으로 가는 길에 사용하는 (네트워크에 연결되지 않은) 노트북 환경에서도 실행할 수 있어야 한다. 테스트가 돌아가지 않는 환경이 하나라도 있다면 테스트가 실패한 이유를 둘러댈 변명이 생긴다. 게다가 환경이 지원되지 않기에 테스트를 수행하지 못하는 상황에 직면한다.
자가검증하는 Self-Validating : 테스트는 부울 bool 값으로 결과를 내야 한다. 성공 아니면 실패다. 통과 여부를 알려고 로그 파일을 읽게 만들어서는 안 된다. 통과 여부를 보려고 텍스트 파일 두 개를 수작업으로 비교하게 만들어서도 안 된다.
테스트가 스스로 성공과 실패를 가늠하지 않는다면 판단은 주관적이 되며 지루한 수작업 평가가 필요하게 된다.
적시에 Timely : 테스트는 적시에 작성해야 한다. 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다. 실제 코드를 구현한 다음에 테스트 코드를 만들면 실제 코드가 테스트하기 어렵다는 사실을 발견할지도 모른다. 어떤 실제 코드는 테스트하기 너무 어렵다고 판명날지 모른다. 테스트가 불가능하도록 실제 코드를 설계할지도 모른다.
테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화하기 때문이다. 그러므로 테스트 코드는 지속적으로 깨끗하게 관리하자.
표현력을 높이고 간결하게 정리하자. 테스트 API를 구현해 도메인 특화 언어 Domain Specific Language, DSL 를 만들자. 그러면 그만큼 테스트 코드를 짜기가 쉬워진다.
테스트 코드가 방치되어 망가지면 실제 코드도 망가진다. 테스트 코드를 깨끗 하게 유지하자.
오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요
그림을 그릴때 스케치를 한다. 스케치 없이 바로 페인트를 칠한다면 숙련된 사람이라도 실수를 하며, 고치는데 시간과 비용을 많이 소모하게 될 것이다. 테스트 코드도 마찬가지 인것 같다. 각 함수마다 테스트를 진행해 완벽한 성을 쌓아야 하지 않을까.
궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.
TDD
개발이 이루어진 다음 그것이 계획대로 잘 완성되었는지 테스트 케이스를 작성하고 테스트하는 타 방식과는 달리, 테스트 케이스를 먼저 작성한 다음 테스트 케이스에 맞추어 실제 개발 단계로 이행하는 개발방법론을 말한다. 묵시적으로 잠재된 상황을 가정하지 않고 테스트 케이스만을 완벽하게 수행하는 것을 목표로 하기 때문에 매우 빠르게 목표를 완료할 수 있다. 한편, TDD 자체가 하나의 테스트가 완전하지 않다는 것을 가정하고 있기 때문에 1차 테스트를 완료한 다음에 새로운 테스트 케이스를 확장해서 작성하고 그것을 통과하기 위한 개발에 들어가는 과정을 끊임없이 반복하여 큰 규모의 프로젝트를 완성해가는 것이다.
오늘 읽은 다른사람의 TIL