본문 바로가기

개발자 강화/개발 독서

[Clean Code 2판] 1-15: Clean Tests

1-15장


Part1.Code

Chapter15. Clean Tests

클린 테스트란?

읽기 쉽고, 빠르고, 격리되어 있고, 반복 가능하고, 자가 검증되며, 시의적절하고, 잘 설계된 테스트이다.

(전부 다 갖추라는 뜻)

 

저자가 강조하는 것은 가독성은 프로덕션 코드보다 단위 테스트에서 더욱 중요할 수 있다는 것이다.

테스트에서는 최소한의 표현으로 최대한 많은 의미를 담아야 한다.

 

좋은 테스트에서는 AAA(Arrange/Act/Assert) 패턴이 구조에서 바로 보인다.

- Arrange: 테스트 데이터 준비

- Act: 동작 실행

- Assert: 결과 검증

 


Domain-Specific Testing Language(DSL)

테스트 개선의 핵심은 테스트를 위한 DSL(도메인 특화 테스트 언어)을 만드는 것이다.

 

시스템을 조작하는 API를 그대로 쓰는 대신, 테스트 전용 함수를 만든다.

테스트를 작성하고 읽는 사람들을 위한 테스트 언어를 만드는 것이다.

 

*Assert를 직역하면 '단언하다'인데, 한글 문맥 상으로 검증으로 읽는 편이 더 직관적이라고 판단했다.

 

Composed Assertion(조합 검증)

여러 개의 저수준 검증을 하나의 의미 있는 단위로 묶는다.

 

처음부터 이렇게 설계되는 건 아니고,

테스트 코드를 지속적으로 리팩토링하는 과정에서 자연스럽게 나타난다.

 

Composed Test Results(조합 테스트 결과)

테스트 결과가 불필요하게 복잡할 때, 이를 이해하기 쉬운 압축된 형태로 줄여주는 기법이다.

 

만약 환경 제어 시스템 테스트를 작성한다고 가정해보자.

대문자를 켜짐, 소문자를 꺼짐으로 정의한다.

 

{Heater, Blower, Cooler, Hi-temp-alaram, Lo-temp-alarm}

 

HBchL = 히터 ON, 블로워 ON, 쿨러 off, 고온 알람 off, 저온 알람 ON

 

14개의 비슷한 테스트가 줄줄이 있어도, 문자열 하나로 상태를 한 눈에 읽을 수 있다.

(이게 이 장에서 가장 흥미로운 부분이었음)

 

Dual Standard(이중 표준)

테스트 결과를 조합해서 문자열로 만드는 것 자체가 컴퓨팅 자원 낭비라고 지적할 수 있지만,

프로덕션에서는 절대 하지 않을 일을 테스트에서는 할 수 있다.

(메모리나 CPU 효율 이슈로부터 자유로움)

 

하지만, 클린 코드가 아니어도 된다는 뜻은 아니다.

테스트 코드도 깔끔해야 한다.

 

성능은 기준에서 자유로울 수 있지만, 가독성을 잃어서는 안된다.

 

The Single Assert Rule(단일 검증 규칙)

좋은 테스트는 한 가지의 사실만 검증한다.

 

이건 테스트에 검증 문이 하나뿐이어야 한다는 뜻이 아니다.

검증문이 여러 개여도, 하나의 논리적인 사실을 검증한다면 좋은 테스트다.

 

위의 환경 제어기 테스트처럼 5개의 assertTrue/assertFalse가 있어도,

전부 합쳐서 '시스템 상태가 이렇다'라는 하나의 사실을 검증한다.

 

The Single Act Rule(단일 행동 규칙)

저자는 더 정확한 표현으로는 단일 행동 규칙을 제시했다.

 

AAA 패턴은 Arrange(준비), Act(행동), Assert(검증) 요소로 구성된다.

테스트할 데이터를 준비하고 -> 데이터에 할 행동을 규정하고 -> 그 행동이 데이터를 올바르게 변환했는지 점검한다.

 

단일 검증 규칙의 목표는 각 테스트가 하나의 행동(Act)만 테스트하도록 보장하는 것이다.

 

오직 준비->행동->검증 구조만 가능하다.

준비->행동->행동->검증->검증 같은 패턴은 안된다.

 

모든 행동은 개별적으로 테스트되어야 하고, 모든 테스트는 독립적이어야 한다.

 

검증 개수에 집착하지 말고, Act가 하나인지를 기준으로 보면 된다.


F.I.R.S.T.

좋은 테스트가 갖춰야 할 특성을 기억하기 쉬운 약자로 정리한 것이다.

 

Fast (빠름)

테스트가 느리면 -> 자주 안 돌림 -> 문제를 늦게 발견 -> 코드 정리 안함 -> 코드 썩음

테스트를 아주 빠르게 설계하라!

 

Isolated(격리됨)

테스트끼리 의존하면 안된다.

한 테스트가 다음 테스트의 조건을 설정하면, 첫 번째 실패가 연쇄 실패를 유발한다.

각 테스트는 독립적으로, 어떤 순서로도 실행 가능해야 한다.

 

Repeatable(반복 가능)

프로덕션 환경, QA 환경, 네트워크 없는 기차 안 노트북에서도 돌아가야 한다.

환경에 의존하면 실패에 대한 변명만 생긴다.

(KTX에서 하는 코딩이 진짜 맛있는데)

 

Self-Validating(자가 검증)

테스트 결과는 boolean이어야 한다.

통과 아니면 실패.

 

로그 파일 뒤적거려서 통과 여부 한단하기, 두 파일을 수동비교하기

그건 테스트가 아니다.

 

Timely(시의적절)

프로덕션 코드와 함께 작성.

다 만들고 나서 테스트 짜면 이미 테스트하기 어려운 구조로 굳어져 있다.

(14장의 테스트 규율과 연결되는 이야기)


Test Design

1-9장: Clean Method: https://developer-dreamer.tistory.com/207

9장에서 살펴봤듯, 테스트는 프로덕션 코드와의 결합도를 낮추도록 설계해야 한다.

 

수백 개의 모듈로 구성된 시스템에서 하나의 변경이 수많은 모듈을 수정하게 만든다면?

=>그건 잘못 설계된 시스템이다.

 

마찬가지로, 잘 설계된 시스템에 수천 개의 테스트가 있는데,

하나의 변경이 수백 개의 테스트를 깨뜨린다면?

=>잘못 설계된 test suite

 

소프트웨어 설계의 원칙과 규칙은 테스트에도 똑같이 적용된다.

 

프로덕션 코드에서 함수 시그니처를 하나 바꿨더니 다른 모듈 수백 개가 영향받는 설계를 한다면,

그 시스템은 설계가 잘못됐다고 자연스럽게 말한다.

 

만약 테스트에서도 그런 일이 일어난다면,

마찬가지로 설계가 잘못됐다고 생각해야 한다.

 

결합도를 최소화해야 한다.


Conclusion

테스트를 썩게 내버려 두면 코드도 썩는다.

테스트 코드에도 프로덕션 코드와 동일한 설계 원칙을 적용하라.

 

테스트가 프로덕션 코드의 유연성, 유지보수성, 재사용성을 보존하고 강화한다.

 


작성: 2026.03.06. 00:13

728x90