테스트하기 어려운 코드를 object graph의 상위쪽으로 옮긴다 (옮기기 전 단계는 결국 테스트할 수 없어지지만, 우리는 모든 코드를 테스트하는게 목표는 아님)
-> 테스트 하기 어려운 부분을 분리해서 핵심로직을 테스트하는게 목적
메소드의 크기가 최대 10라인을 넘지 않도록 구현
method가 한 가지 일만 하도록 최대한 작게 만들어라.
TDD를 잘하려면 특정 시점의 상태를 잘 생각해내야함.
- 예를 들어, 우승자를 구하는 로직을 테스트한다면, 경기가 끝난 상태의 자동차들을 Given으로 줘야함.
모델(도메인) 객체에서는 getter, setter 쓰지 마라. DTO, 혹은 view에 전달할 때는 getter 허용
생성자는 다른 생성자를 호출하도록 구현
테스트 코드를 위해 만든 생성자로 잘못 세팅하는 경우가 생기는걸 막으려면… 팩토리 클래스를 만들어서 실제 관리 포인트를 하나로 만드는 방법도 있다.
public class carFactory {
public static void create() {
}
}
생성자는 마음껏 늘리면서 public 메소드의 수는 최대한 줄여라
접근제어자는 최소한만 오픈 -> 필요하면 더 열기.
상태값이 없는 클래스의 메서드는 Static으로 해도 괜찮다
가장 좋은건 클래스의 인스턴스 변수가 클래스 내 모든 메서드에서 쓰일 수 있도록 설계되는 것.
테스트 하기 어려운 부분은 쿨하게 테스트 안해도 됨 -> 테스트 하기 쉬운 부분과 어려운 부분을 분리하는 연습 필요(출력, DB CRUD.. 이런건 엔드투엔드 테스트, 통합테스트에서 해야함. 단위테스트X. 핵심 비즈니스로직이 없음)
모킹은 가능한 사용하지 않기(가독성이 떨어지고 유지보수가 어렵다)
자바에서도 final 적극 활용 (ex_변경되지 않는 메서드의 매개변수..)
UI, DB 등과 의존관계를 가지지 않는 핵심 도메인 영역을 집중 설계
view <-> controller <-> domain
도메인과 뷰는 의존관계를 갖지 않는다.
갖더라도 view -> domain 방향만 허용
테스트는 경계값으로 (모든 값으로 할 수 없기 때문에)
total, sub,average, max, min, record, string, pointer 등 한정자를 써야한다면 이름의 끝에! (ex. expenseTotal..)
오픈소스 코드를 많이 읽어보기 (JDK, Spring 프레임워크 등)
도메인 지식을 쌓기 위해 노력
private 메서드가 늘어나는 것에 대한 거부감을 없애기
private 메서드들은 퍼블릭을 통해 테스트 하기.
priavte에 로직이 너무 많다면 여러 클래스의 역할을 하나에서 하는게 아닌지 의심해봐야함.
클래스의 인스턴스 변수를 최대한 줄여라 (즉 클래스가 가지는 상태값.) -> 상태값을 여러군데에서 유지하면 변경될때마다 바꿔줘야함. 데이터 중복의 문제.. (ex) cars와 winners를 따로 가질 필요 없음. 그냥 필요할 때 winners를 구하는게 훨씬 좋음)
비즈니스 로직과 UI 로직을 분리(ex. car에서 print 메서드를 갖는것)
fixture -> 테스트를 위해 필요한 초기 데이터. 테스트의 인스턴스 변수는 모든 테스트에 공통으로 필요한 픽스쳐만. 테스트마다 달라지는거는 각 테스트로 옮기기
@BeforeEach에는 각 테스트에서 중복으로 사용하는 픽스쳐만 초기화
한번 만들어진 후 외부에 의해 값을 바꿀 수 없는 Immutable 객체로 바꾸기
- ex) 리턴할때 new Position(n) 과 같은 식으로 반환 -> 인스턴스가 많이 만들어진다는 단점. 이정도의 성능 저하는 이슈가 되면 그때 바꿔도 괜찮음.
값의 유효 범위 -> 객체에서 관리
무항 메서드를 지향하기. 3개 이상은 가급적 사용X. 4개 이상은 절대x(특별한 이유가 있어도)
3개 이상의 인스턴스 변수를 가진 클래스를 만들지 마라
-> 너무 많으면 관련있는 애들을 묶어서 새로운 클래스로 만들기
값을 바꾸도록 쿼리하는 부분과 값을 가져오는 부분을 분리하는 것과 분리하지 않는것.
1)
public Position move() {
position = position + 1;
return this;
}
2)
public void move() {
position = position + 1;
}
public int getPosition() {
return position;
}
뭐가 더 맞고 어떤 상황에서 뭐가 더 좋은지 본인이 기준을 찾기.. 백프로 정답은 없음.
구현체가 실제 코드 쪽에 1개, 그리고 테스트 쪽에도 존재
-> 이게 결국 DI(의존 관계 주입). 이걸 잘써야 유연하고 테스트 쉬운 코드가 만들어짐
-> 자바 8에 있는 람다(함수를 인자로 전달 == 인터페이스의 구현체, 익명 클래스, 구현해야할 메소드가 하나일때만 람다로 대체 가능, @FuntionalInterface 를 통해 강제 가능)를 쓰면 코드가 매우 간결해짐