TIL(Today I Learned)
기억하고싶은 내용 📝
8장. 경계
외부 코드 사용하기
- 경계 인터페이스를 이용할 때는 이를 이용하는 클래스나 클래스 계열 밖으로 노출되지 않도록 주의한다. (146p)
경계 살피고 익히기
- 만약 외부에서 가져온 패키지를 사용하고 싶다면 어디서 어떻게 시작해야 좋을까? 외부 패키지 테스트가 우리 책임은 아니다. 하지만 우리 자신을 위해 우리가 사용할 코드를 테스트하는 편이 바람직하다. (146p)
- 곧바로 우리쪽 코드를 작성해 외부 코드를 호출하는 대신 먼저 간단한 테스트 케이스를 작성해 외부 코드를 익히면 어떨까? 짐 뉴커그는 이를 학습 테스트라 부른다. (147p)
학습 테스트는 공짜 이상이다
- 학습 테스트는 패키지가 예상대로 도는지 검증한다. 일단 통합한 이후라고 하더라도 패키지가 우리 코드와 호환되리라는 보장은 없다. (149p)
- 학습 테스트를 이용한 학습이 필요하든 그렇지 않든, 실제 코드와 동일한 방식으로 인터페이스를 사용하는 테스트 케이스가 필요하다. 이런 경계 테스트가 있다면 패키지의 새 버전으로 이전하기 쉬워진다. (150p)
깨끗한 경계
- 소프트웨어 설계가 우수하다면 변경하는데 많은 투자와 재작업이 필요하지 않다. (151p)
- 경계에 위치하는 코드는 깔끔히 분리한다. 또한 기대치를 정의하는 테스트 케이스도 작성한다. (152p)
- 통제가 불가능한 외부 패키지에 의존하는 대신 통제가 가능한 우리 코드에 의존하는 편이 훨씬 좋다. (152p)
- 외부 패키지를 호출하는 코드를 가능한 줄여 경계를 관리하자. (152p)
9장. 단위 테스트
TDD 법칙 세 가지
첫째 법칙: 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
둘째 법칙: 컴파일은 실행하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
셋째 법칙: 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
깨끗한 테스트 코드 유지하기
- 테스트 코드는 실제 코드 못지 않게 중요하다. 테스트 코드는 이류 시민이 아니다. 테스트 코드는 사고와 설계와 주의가 필요하다. 실제 코드 못지 않게 깨끗하게 짜야 한다. (157p)
- 테스트는 유연성, 유지보수성, 재사용성을 제공한다. (157p)
- 테스트 케이스가 없다면 모든 변경이 잠정적인 버그다. 아키텍처가 아무리 유연하더라도, 설계를 아무리 잘 나눴더라도, 테스트 케이스가 없으면 개발자는 변경을 주저한다. 버그가 숨어들까 두렵기 때문이다.
- 실제 코드를 점검하는 자동화된 단위 테스트 슈트는 설계와 아키텍처를 최대한 깨끗하게 보존하는 열쇠다.
깨끗한 테스트 코드
- 깨끗한 테스트 코드를 만들려면? 세 가지가 필요하다. 가독성, 가독성, 가독성.
- 테스트 코드는 최소의 표현으로 많은 것을 나타내야 한다.
이중 표준
- 테스트 API 코드에 적용하는 표준은 실제 코드에 적용하는 표준과 확실히 다르다. 단순하고, 간결하고, 표현력이 풍부해야 하지만, 실제 코드만큼 효율적일 필요는 없다.
테스트당 assert 하나
- assert문이 하나인 함수는 결론이 하나라서 코드를 이해하기 쉽고 빠르다.
테스트당 개념 하나
- "테스트 함수마다 한 개념만 테스트하라."
- 여러 개념을 한 함수에 몰아넣으면 독자가 각 절이 거기에 존재하는 이유와 각 절이 테스트하는 개념을 모두 이해해야 한다.
F.I.R.S.T.
깨끗한 테스트는 다음 다섯 가지 규칙을 따른다.
- 빠르게
Fast: 테스트는 빨라야 한다. 테스트가 느리면 자주 돌리지 않게 되며, 초반에 문제를 찾아내 고치지 못해 코드의 품질이 망가진다.
- 독립적으로
Independent: 각 테스트는 서로 의존하면 안된다. 각 테스트는 독립적으로 그리고 어떤 순서로 실행해도 괜찮아야 한다.
- 반복가능하게
Repeatable: 테스트는 어떤 환경에서도 반복 가능해야 한다. 테스트가 돌아가지 않는 환경이 하나라도 있다면 테스트가 실패한 이유를 둘러댈 변명이 생긴다.
- 자가검증하는
Self-Validating: 테스트는 부울 값으로 결과를 내야 한다. 성공 아니면 실패다.
- 적시에
Timely: 테스트는 적시에 작성해야 한다. 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.
결론
- 테스트 코드는 실제 코드만큼이나 프로젝트 건강에 중요하다.
- 테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화한다.
- 테스트 코드를 지속적으로 깨끗하게 관리하다. 표현력을 높이고 간결하게 정리하자.
- 테스트 API를 구현해 도메인 특화 언어(DSL)를 만들자.
- 테스트 코드가 방치되어 망가지면 실제 코드도 망가진다. 테스트 코드를 깨끗하게 유지하자.
오늘 읽은 소감
테스트 코드를 짜는 것이 중요하지만 실제 코드와 맞먹을 정도로 방대한 테스트 코드는 관리하기 어려워 진다는 것을 알게되었다. 마치 배보다 배꼽이 큰 것. 그렇기 때문에 최소의 표현으로 많은 것을 나타내는 것이 중요하다. 코드의 품질을 높이기 위해 테스트 코드를 잘 짜자. 잘 짠 테스트 코드는 실제 코드를 잘 짜기위한 비계scaffolding의 역할을 할 것이다.
용어 정리
- 학습 테스트: 프로그램에서 사용하려는 방식대로 외부 API를 호출하여 통제된 환경에서 API를 제대로 이해하는지를 확인하는 방법. 학습 테스트는 API를 사용하려는 목적에 초점을 맞춘다.
- TDD(Test Driven Development): 테스트 주도 개발. 반복 테스트를 이용한 소프트웨어 방법론으로, 작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현한다. 짧은 개발 주기의 반복에 의존하는 개발 프로세스이다.
- DSL(Domain-Specific Languages): 도메인 특화 언어는 관련 특정 분야에 최적화된 프로그래밍 언어. DSL은 해당 분야 또는 도메인의 개념과 규칙을 사용한다.
참고자료
도메인 특화 언어 (DSL: Domain-Specific Languages)
TDD 방법론 (테스트 주도 개발) - 알기 쉽게 정리 [Inpa Dev 👨💻:티스토리]
DAY 12: 단위 테스트
TIL-Assignment#10(2022.03.05[토] ~ 06[일])
💖 나의 최애 북틸
chillihc님의 velog
: 핵심 내용 위주로 간결하게 작성되어 가독성이 좋은 글
Catsbi's DLog
: 예제 코드와 함께 볼 수 있어서 이해가 잘되는 글
TIL_by madang
: 현업에서 느낀점을 서술하여 기억에 남는 글