////
Search
Duplicate
🎖️

14. 테스트와 가독성

이 장은 간결하고 효과적으로 텍스트를 작성하는 방법에 대해 알아본다.

읽거나 유지보수하기 쉽게 테스트를 만들어라

다른 프로그래머가 수정하거나 새로운 테스트를 더하기 쉽게 테스트 코드는 읽기 쉬워야 한다.
테스트 코드를 작성하는 것은 지금 시점에 이르러 선택이 아닌 필수가 되었기 때문에 작성하는 것은 여지가 없다. 즉 작성은 필수니 작성할 땐, 가독성 좋게 작성해야 한다는 것이다.
또한 테스트는 특정한 동작 단위로 설계되므로 해당 동작을 설명하는 가장 좋은 예시가 되고는 한다.

테스트를 더 읽기 쉽게 만들기

일반적인 설계원리를 따른다면 비즈니스 로직이 아닌 구현 세부 사항은 사용자가 볼 필요가 없으므로 숨겨서 더 중요한 내용이 눈에 잘 띄게 해야한다.
테스트도 그렇다. 테스트의 목적은 메소드에서 드러나는데, 이는 보통 코드 블록보다 추상화 수준이 한, 두 단계 높아야한다.
코드 블록 내의 추상화 수준이 뒤죽박죽이라면 가독성을 깨치는 행위다. 코드 블록의 뎁스가 1칸으로 유지하듯이 추상화 수준도 한, 두 단계 내려가는 것을 유지해야 한다.
프로덕트 코드를 리팩토링할 때 사용했던 방법인 메소드를 먼저 적어보기도 좋은 방법이다.

읽기 편한 메시지 만들기

검증 라이브러리를 사용해서 assert문의 가독성을 그대로 두지 말아라.
추출할 필요는 없지만 굳이 가독성이 썩 좋지않은 테스트 프레임워크 내장 assert 대신 더 나은 가독성을 제공하는 라이브러리를 사용하라는 것이다.

좋은 테스트 입력값의 선택

테스트에 적절한 입력값을 선택하는 기술도 있다. 좋은 입력값은 코드를 구석구석 철저하게 테스트한다. 하지만 이는 간단해서 읽기도 쉬워야 한다.
가능하면 가장 간단한 입력으로 코드를 완전히 검사할 수 있어야 한다.
요구사항이 음수라면 -1234234를 사용하지말고 -1정도만 되어도 충분하다는 것이다.
필요한 작업을 수행하는 범위에서 가장 명확하고 간단한 테스트 값을 선택하라.
코드를 구석구석 철저하게 테스트하고자 완벽한 입력을 찾는 것 대신 작은 테스트를 여러 개 사용하라.

테스트 함수에 이름 붙이기

테스트 코드는 주로 메소드 단위로 만들어진다. 테스트하려는 메소드나 상황에 메소드를 하나씩 만들게 된다.
테스트 함수를 위해 좋은 이름을 지어주어야 한다. 전혀 의미가 없는 이름을 사용하면 곤란하다. 테스트를 상세하게 묘사할 수 있는 이름이 좋다.
다음과 같은 항목들이 드러나면 좋다.
테스트되는 클래스
테스트되는 함수
테스트되는 상황이나 버그

테스트 코드를 개선시킬만한 아이디어

테스트가 너무 길고 비즈니스 로직이 아닌 구현 세부 사항을 담고 있지는 않은가 생각해보자.
새로운 검증문을 추가하기 쉬운지 생각해보자.
테스트 실패 메시지가 적절한 정보를 제공하는 지 고민해보자. 디버깅에 도움이 되어야 한다.
모든 것을 한 꺼번에 테스트하려고 애쓰는지 생각해보자. 나누면 쉬워진다.
테스트 입력이 간단한가에 대해 고민해보자. 내가 제공한 값이 특별한 의미가 있는지, 없다면 간략화하는 것이 좋다.
테스트 입력값과 검증문이 코드를 충분히 테스트하는 지 생각해보자.
테스트 메소드 명이 적절한지 고민해보자.

테스트에 친숙한 개발

테스트하기 용이한 개발은 잘 정의된 인터페이스를 가지고 지나치게 많은 상태나 동작을 포함하지 않으며 감추어야할 데이터를 노출시키지 않는다.
테스트하기 용이한 설계는 서로 다른 책임을 가진 부분을 서로 분리된 부분으로 구상하는 전체적으로 봤을때 잘 조직된 코드를 낳는다.
테스트하기 힘든 코드의 특징은 다음과 같다.
전역변수를 사용한다. 다른 말로는 공유 의존성을 사용한다.
테스트할 때마다 모든 전역 변수를 초기화해야하기 때문이다. 적절히 초기화가 이루어지지 않을 경우, 테스트가 독립된 상태로 실행되지 않을 가능성이 있다.
코드가 많은 외부 컴포넌트를 사용한다.
외부 의존도가 높은 테스트는 피드백 속도가 느리고 실패할 가능성을 가늠할 수 없다.
코드가 비결정적인 행동을 가진다.
프로그램이 경합 조건이나 재현하기 어려운 버그를 가지고 있을 확률이 높다.
테스트하기 좋은 코드의 특징은 다음과 같다.
클래스들이 내부 상태를 적게 가지고 있다.
캡슐화된 멤버가 적으므로 테스트 작성이 수월하고 설계상 이해하기도 쉽다.
클래스/함수가 한 번에 하나의 일만 수행한다.
클래스가 다른 클래스에 의존하지 않고 서로 상당히 떨어져있다.
각 클래스가 독립적으로 테스트되며 병렬적으로 개발이 가능하다.
함수들이 간단하고 잘 정의된 인터페이스를 가지고 있다.

지나친 테스트

테스트에 집중한다고 좋은 것이 아니다. 뭐든 도가 지나치면 화를 낳는 법이다. 다음은 몇 가지 예다.
테스트를 가능하게 하려고 제품 코드의 가독성을 희생시키는 경우, 테스트 코드를 작성하는 것은 윈윈이 되어야 한다.
100% 코드 테스트에 집착하는 일, 모든 코드를 테스트하려하지 말자. 가성비가 좋지 않은 행위다.
버그가 야기하는 비용이 어느 정도인가에 따라 테스트 비용이 결정된다.
테스트 코드로 실제 제품 개발에 차질을 빚게되는 경우, 테스트 코드를 작성하는 것은 프로젝트의 일부다. 프로젝트보다 우선시 되어서는 안된다.

요약

테스트를 개선하기 위한 구체적인 항목은 다음과 같다.
각 테스트의 최상위수준은 간결해야 한다. 이상적으로는 각 테스트의 입출력이 한 줄의 코드로 설명될 수 있어야 한다.
테스트에 실패하면 버그를 추적해서 디버깅에 도움이 되는 에러 메시지를 출력해야 한다.
코드의 구석구석을 철저하게 실행하는 가장 간단한 입력을 사용하라.
무엇이 테스트되는지 분명하게 드러나도록 테스트 함수에 충분한 설명이 포함된 입력을 부여하라.
무엇보다도 테스트의 수정이나 추가가 쉬워야 한다.