💋 단위 테스트에 대한 생각
내가 단위 테스트를 작성하는 이유는 무엇인가?
단위 테스트를 작성하면 마음이 편안하기 때문이다. 리팩터링을 할 때에도 어떤 부분에서 문제가 될 지에 대해 걱정하지 않고 코드를 수정할 수 있다. 세부 구현에 대해 코드 품질을 높일 때 특히 효과적이라고 생각했다.
하지만 이번 체스 미션 중에 단위 테스트를 빗겨가는 케이스를 두 번이나 생각해내지 못했고, 테스트 코드의 맹점은 완벽하지 않은 테스트가 신뢰될 때라는 것을 깨달았다. 앞으로는 조금 덜 맹신하면서 테스트 코드를 작성할 필요가 있을 것 같다. 항상 놓치는 케이스가 없는지 신경쓰면서 작성해야겠다.
내가 작성한 좋은 단위 테스트는 어떠한 부분에서 좋은 단위 테스트라 느꼈는가?
단위 테스트 첫 강의 때도 언급했었지만, 나는 프로덕션 코드의 내용을 변경시키지 않으며, 프로그램의 작은 부분과 전체에 대한 부분을 모두 테스트할 수 있는 단위테스트를 좋은 테스트라고 생각한다. 이렇게 생각하게 된 데에는 안좋은 단위테스트를 작성한 경험이 있어서인데, 프로덕션 코드에 static한 변수 중에서 그 변수의 타입이 가변객체일 때 테스트하는 데 굉장히 어려움을 겪었다. 예를 들어서, static 클래스 변수로 List를 관리하고 있다면 내부에 add하고 연산하는 메서드를 테스트 한 후 내가 수정한 모든 내용들을 지우는 과정까지 반드시 AfterAll로 추가해야만 했다. 굉장히 구린 테스트 코드라고 볼 수 있다. 나만 이런가 해서, 이전에 테코톡에서 단위 테스트를 다루었던 제이(불확실)한테 질문했었는데, 제이도 같은 방법을 사용한다고 했다.
이 경우에 두 가지 해결책이 있다.
1.내가 작성한 static 변수가 정말로 static해야 하는지 우선 살펴보면서 내가 작성한 코드가 테스트하기 안좋은 코드는 아닌지 살펴볼 필요가 있다. 대다수의 경우에 내가 잘못한 것이었다.
2. 반드시 static해야 한다면, 테스트 코드 내에서 변경시키지 않거나 테스트하지 않는 것도 하나의 방법이다.
질문에 대한 내용과 정확히 맞지는 않지만, 프로그램의 작은 부분에 대해서 테스트하면서 큰 부분에 대해서 동시에 테스트해야 하는지에 관한 고민이 많았는데, 지금은 굳이 둘 다 테스트할 필요는 없을 것 같다. 진리의 케바케! 항상 이 테스트를 하나 더 작성해보는 것의 비용을 생각해서 잘 재본다면 최선의 선택이 될 것 같다.
위와 같은 좋은 단위 테스트를 작성하기 위해 어떠한 시도를 해볼 수 있는가?
좋은 단위테스트는 테스트 코드만을 잘 작성하는 것으로 된다고 생각하지 않는다. 테스트하기 쉬운 코드를 작성하는 것부터가 중요하다. 프로덕션의 내용을 변경시키지 않기 위해서는 프로덕션 코드 내부에서 의존성을 주입받는 방식을 잘 활용해야 한다고 생각한다.
랜덤한 요소는 이전까지 테스트하기 굉장히 어려웠다. 많은 고민 끝에 지금은 아래와 같이 테스트하고 있다.
먼저 코드 내에서 랜덤한 요소가 들어와야 하는 부분을 전략 패턴으로 분리해 낸다.
public class Ladder {
private final List<Line> lines;
public Ladder(int count, Height height, LadderStepGenerator ladderGenerator) {
this.lines = createLadder(count, height, ladderGenerator);
}
private static List<Line> createLadder(int count, Height height, LadderStepGenerator ladderGenerator) {
List<Line> lines = new ArrayList<>();
for (int i = 0; i < height.getValue(); i++) {
lines.add(new Line(count, ladderGenerator));
}
return lines;
}
}
내가 필요한 동작에 대해서 인터페이스를 생성한다.
public interface LadderStepGenerator {
LadderStep generate();
}
인터페이스를 implement해서, 프로덕션 코드에서 사용할 클래스를 만든다. 프로덕션 코드에서는 랜덤한 요소를 그대로 사용한 결과를 반환한다.
public class RandomLadderStepGenerator implements LadderStepGenerator {
private final Random random = new Random();
@Override
public LadderStep generate() {
if (random.nextBoolean()) {
return LadderStep.EXISTS;
}
return LadderStep.NONE;
}
}
테스트 코드에서 사용하기 위한 클래스를 만든다. 이 때는 랜덤한 요소를 배제해, 예측 가능한 결과를 반환한다.
public class ExistsLadderStepGenerator implements LadderStepGenerator {
@Override
public LadderStep generate() {
return LadderStep.EXISTS;
}
}
이렇게 다양한 방법들을 공통 인터페이스인 LadderStepGenerator를 통해 코드에서 갈아끼울 수 있기 때문에 굉장히 테스트하기 용이하다.
💋 코드 품질에 대한 생각
코드 품질이 중요한 이유 중 가장 와닿는 이유는 무엇인가?
코드 품질이 중요한 이유는 정말 많은데, 강의 자료에 있던 내용은 아래와 같다.
우선 잘 작동하는 것은 굉장히 기본이라고 생각한다. 아마도 1순위일 것 같다.
위 이유를 만족하기 위한 코드를 작성하기 위해 어떠한 노력을 해봤는가? 혹은 할 예정인가?
위에서 언급한 1순위인 잘 작동하는가의 뒤로는 모든 사람과 각 회사마다의 우선순위가 다를 것 같은데, 읽기 좋고 보기 좋은 것은 상당히 주관적이다. 따라서 나와 함께 일하는 사람들이 공통적으로 사용하는 습관과 같은 것들을 잘 지켜야 한다고 생각한다. 좋은 품질의 코드를 작성하기 위해서는 나의 고집을 조금 버리고, 주변의 약속을 따르는 것도 필요하다고 생각한다.
관리하기 쉬운 코드, 테스트하기 좋은 코드는 결국 많은 개발자들이 고민하는 객체 지향적 설계, 혹은 함수형 프로그래밍의 패러다임에 대해 공부하면서 차차 몸으로 느껴 나가야 한다고 생각한다. 효율성에 관한 것은 소프트웨어를 장인 정신으로 바라보는 개발자에게는 적합하지 않을 테지만, 언제나 시간과 자원은 제한적이라는 생각을 하며 작업한다면 회사에서 원하는 효율성에 대한 기준도 맞출 수 있을 것 같다.
코드 품질을 높은 코드를 작성하는 프로그래머가 훌륭한 프로그래머인가? 그렇게 생각한 이유는 무엇인가?
훌륭한 프로그래머이지 않을까? 낮은 코드의 품질로 회사의 코드를 떡칠하고, 무수히 많은 공개 메서드 선언으로 세부 구현에 손댈 수도 없는 API를 만들었다고 생각해보자... 과연 나는 짤릴까? 어쩌면 개발자들은 서로 코드에 대해서 면밀히 보지 않으면 누군가가 얼마나 좋은 코드를 쓰는지 모를 수도 있다. 객관적으로 좋은 품질의 코드는 판단할 수 없다고 생각한다. 어딘가에서 좋은 코드는 다른 누군가에게는 최악의 코드일 수도 있다. 따라서 주변 사람들에게 잘 보이기 위해서 읽기 좋고 보기 좋은 코드가 중요하다고 생각한다.
시간이 부족하다면 조금 테스트하기 어렵더라도 비용이 적게 들어가는 코드를 작성하는 것이 팀을 위한 최선의 선택이 될 수도 있다. 과연 테스트하기 좋은 코드, 객체 지향적 코드를 작성하기 위해서 마감을 지키지 못하는 프로그래머와 코드의 품질을 조금 포기하되 제때 제출할 수 있는 프로그래머 중 누가 더 좋은 프로그래머일까..?