Chapter 09, 10
9장 단위 테스트
애자일과 TDD 로 단위테스트를 자동화 하는 프로그래가 늘어나는 추세.
TDD 법칙 세 가지
- 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
- 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성.
- 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성.
이 규칙을 따르면 테스트 코드와 실제 코드가 함께 나옴.
하지만 실제 코드를 전부 테스트 하는 방대한 테스트 코드는 관리문제를 유발하기도 함.
깨끗한 테스트 코드 유지하기
일회용 테스트 코드와 자동화된 단위 테스트 슈트는 간극이 매우 큼.
테스트 코드가 지저분할수록 변경하기 어려워지며,
테스트 코드가 복잡하면 유지보수하는 비용도 늘어나게 된다.
테스트 코드는 실제 코드 만큼 중요하다.
테스트 케이스가 없으면 모든 변경이 잠정적 버그다.
테스트는 유연성, 유지보수성, 재사용성을 제공함 - 테스트 케이스가 있으면 변경이 쉬워지기 때문.
깨끗한 테스트 코드
가독성은 테스트 코드에 중요 - 명료성, 단순성, 풍부한 표현력
테스트 코드는 진짜 필요한 자료 유형과 함수만 사용.
헷갈리는 세세한 코드를 줄여, 빠르게 코드를 이해하도록 만듬.
함수와 유틸리티를 구현해 테스트 코드에 사용하면 좀더 간결해짐.
실제 환경에서는 안되나 테스트 환경에서 문제없는 방식도 있음 - 이중 표준
테스트 당 assert 하나
함수 이름에 given-when-then 을 사용해 테스트 코드를 읽기 쉽게 만듬.
Template Mathod 패턴을 사용하면 중복 제거 가능.
given / when 을 부모 클래스에 두고 then 을 자식 클래스에 둠.
@Before 함수에 given / when 부분을 넣고, @Test 함수에 then 을 넣어도 됨.
단일 assert 문은 훌륭한 지침. assert 문 개수는 최대한 줄이면 좋다.
테스트 함수마다 한 개념만 테스트하라.
F.I.R.S.T
- Fast
- Independent
각 테스트는 서로 의존하면 안됨. - Repetable
어떤 환경에서도 반복 가능하게 - Self-Validating
성공 아니면 실패. bool 값으로 결과 - Timely
실제 코드를 구현하기 직전에 구현.
결론
테스트 코드는 실제 코드의 유연성, 유지보수성, 재사용성을 보존 강화하기 위한것.
10장 클래스
클래스 체계
클래스를 정의하는 표준 자바 관례
- 가장먼저 변수 목록이 나옴.
static public 상수 먼저, static private 변수, private 인스턴스 변수 순서. - public 함수 이후 private 함수는 자신을 호출하느 public 함수 직후에 나옴.
- 캡슐화
변수와 유틸리티 함수는 공개하지 않는 편이 낫지만 반드시 그렇지는 않음.
때로 변수나 유틸리티 함수를 protected 로 선언 테스트 코드 접근 허용하기도 함.
캡슐화를 풀어주는 결정은 항상 최후의 수단임.
클래스는 작아야 한다!
클래스가 맡은 책임의 수로 크기를 측정.
클래스 이름은 클래스의 책음을 기술해야 하는데, 모호하거나 간결한 이름이 아니면 그 클래스의 책임이 너무 많은 것.
- 단일 책임 원칙 SRP
클래스나 모듈을 변경할 이유가 단 하나 뿐이어야 한다는 원칙.
변경할 이유를 파악하다보면 코드를 추상화하기도 쉬워짐.
작은 서랍을 많이 두고 기능과 이름이 명확한 컴포넌트를 나눠 넣고 싶은가?
아니면 큰 서랍 몇 개를 두고 모두를 던져넣고 싶은가?
큰 클래스 몇개가 아니라 작은 클래스 여럿으로 이뤄진 시스템이 더 바람직
작은 클래스들이 협력해 시스템에 필요한 동작을 수행.
- 응집도
클래스는 인스턴스 변수 수가 작아야 함.
일반적으로 메서드가 변수를 더 많이 사용할수록 메서드와 클래스는 응집도가 높음.
함수는 작게, 매개변수 목록을 짧게하는 전략.
- 응집도를 유지하면 작은 클래스 여럿이 나온다.
몇 함수가 몇 변수만 사용한다면 독자적인 클래스로 분리해도 됨.
클래스가 응집력을 잃는다면 쪼개라.
리팩터링한 프로그램은 좀 더 길고 서술적인 변수 이름을 사용.
코드에 주석을 추가하는 수단으로 함수 선언과 클래스 선언을 활용.
가독성을 높이고자 공백을 추가하고 형식을 맞춤.
정확한 동작을 검증하는 테스트 슈트를 작성
-> 한번에 하나씩 여러번 코드를 변경. -> 변경할 때 마다 테스트를 수행해 확인.
변경하기 쉬운 클래스
클래스를 체계적으로 정리해 변경에 따르는 위험을 낮춰야 함.
- 변경으로부터 격리
요구사항은 변하며 코드도 변함.
상세 구현에 의존하는 클라이언트 클래스는 구현이 바뀌면 위험함.
인터페이스와 추상 클래스를 사요해 구현이 미치는 영향을 격리해야함.
시스템의 결합도를 낮추면 유연성과 재사용성이 높아짐.
DIP Dependency Inversion Principle : 클래스가 상세한 구현이 아니라 추상화에 의존해야 한다는 원칙.