[단위테스트] 테스트 리팩토링

Jiwoo Kim·2021년 4월 3일
0

단위테스트와 JUnit

목록 보기
9/9
post-thumbnail

💡 테스트 코드 유지 보수 비용 최소화하기

테스트 코드는 상당한 투자를 요구한다. 비용 증가를 방지하기 위한 여러 테스트 문제들을 해결하는 방법을 알아보자.


테스트 냄새

Test smell: 테스트 코드에 존재하는 문제점


불필요한 코드

try/catch 블록

테스트가 예외를 기대하는 것이 아니면, 즉 명시적으로 예외를 던지는 단계가 있는 것이 아니라면 try/catch 블록은 필요없다. 그냥 예외를 throw하면 된다. JUnit은 테스트를 실행하며 발생한 오류를 자동으로 catch해서 stacktrace를 출력한다.

not-null 체크

프로덕션 코드에서는 객체를 참조하기 전 예외를 방지하기 위해 not-null 체크를 해야 한다. 하지만 테스트 코드에서는 알아서 JUnit이 null 참조 예외를 잡아 오류로 처리하기 때문에 필요하지 않다.


추상화 누락

추상화로 필수적인 개념을 최대화하고 불필요한 세부 사항은 감춰야 한다.

TypeSafeMatcher

사용자 정의 Matcher를 구현하면 클래스 코드량은 늘지만, 테스트 코드를 간결하게 작성할 수 있게 된다. 따라서 테스트를 이해하려는 노력을 단순화할 수 있다. 또한, 많은 추가 테스트에 Matcher를 재활용할 수 있으므로 생산성을 높일 수 있다.

대체 추상화

assertThat(instance.size(), equalTo(0));  // 누락된 추상화 개념: Emptiness
assertTrue(instance.isEmpty());           // 크기 비교라는 불필요한 노력 제거

부적절한 정보

테스트에는 부적절하지만 당장의 컴파일만을 위해 넣는 데이터는 혼란과 오류를 초래한다.

Magic Literal

실제 코드 작동에 영향을 주지 않으면서 하드 코딩된 String, 숫자를 Magic Literal이라 한다. 혼란을 방지하고 인자의 의미를 명확하게 밝히기 위해 상수로 표현해야 한다. 상수의 이름은 ANY_TITLE, ARBITRARY_TITLE 등으로 지정하여, 신경 쓰지 않는 데이터라는 것을 밝히는 것이 좋다.


부푼 생성

필요한 객체를 생성하는 도우미 메서드를 생성하여 장황한 생성문을 분리해야 한다. 이를 통해 구현 세부 사항을 추상화하여 테스트 이해 속도를 높일 수 있다.


다수의 단언

테스트마다 단언을 하나 또는 두 개로 최소화하여 테스트 케이스를 하나만 포함하도록 해야 한다. 이를 통해 단일 목적의 테스트를 구현하고, 불필요한 주석을 줄이고, 테스트 이름을 개선할 수 있다.


테스트와 무관한 세부 사항들

군더더기를 @Before@After 메서드로 이동해야 한다. 자원 관리, 로깅 관리 등을 테스트 로직과 혼동되지 않도록 분리하면 테스트를 이해하기 더 쉬워진다.


잘못된 조직

AAA 부분을 명확하게 명시하여 테스트 파악을 쉽게 만들어야 한다. 준비, 실행, 단언 사이에 빈 줄을 삽입하여 의도를 분명하게 밝혀야 한다.


암시적 의미

테스트 데이터를 명시적으로 바꿔야 한다. 슬쩍 보아도 "왜 그러한 결과를 기대하는가?"에 분명하게 대답할 수 있는 테스트를 만들어야 한다.



"프로덕션 코드를 깔끔하고 간결하게 리팩토링하고, 프로덕션 코드를 설계할 때 더 많은 유연성을 제공하도록 리팩토링하고, 시스템의 의존성 도전 과제에 대해 목을 지원하고, 유지 보수 비용을 최소화하고, 이해도를 최대화하도록 테스트를 리팩토링하는 것이 설계이다." (p.245)

0개의 댓글