[클린코드] 9장. 단위 테스트

MEUN·2022년 3월 5일
1

< CLEAN-CODE />

목록 보기
12/17
post-thumbnail

3 주차

일 | Assignment #13

  • 📚 9장. 단위 테스트
  • ✔️ TIL

9장. 단위 테스트


📘 책에서 기억하고 싶은 내용

  • TDD 법칙 세 가지 (p.155)
    • 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.
    • 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위 테스트를 작성한다.
    • 현재 실패하는 테스트를 통과할 정도로만 실제 코드를 작성한다.
  • TDD 로 인하여 제대로 된 테스트 케이스를 작성해야 한다는 사실을 간과하지 말아야 하지만,
    위와 같은 규칙을 따르면 실제 코드와 맞먹을 정도로 방대한 테스트 코드가 생성되어 심각한 관리 문제를 유발하기 전에 관리가 필요하다.
  • 깨끗한 테스트 코드 유지하기 (p.156)
    • 지저분한 테스트 코드를 작성하는 것은 테스트를 아예 하지 않는 것보다 못하다.
    • 실제 코드가 진화하면 테스트 코드도 변해야 하지만, 테스트 코드가 지저분할수록 변경하기 어려워져 결국 코드를 정리하지 않게 되면서 TDD를 포기하게 되는 경지에 이르게 된다.
    • 테스트는 유연성, 유지보수성, 재사용성을 제공한다.
      • TC(Test Case) 가 있으면 변경이 두렵지 않아 코드에 유연성, 유지보수성, 재사용성을 제공할 수 있게 된다.
      • TC가 없다면 모든 변경이 잠정적인 버그다.
      • 테스트 코드가 지저분하면 코드를 변경하는 능력이 떨어지며 코드 구조를 개선하는 능력도 떨어진다.
  • 깨끗한 테스트 코드 (p.158)
    • 깨끗한 테스트 코드 작성에는 가독성이 제일 중요하며, 실제 코드보다 더 중요하다.
    • BUILD-OPERATE-CHECK 패턴이 테스트 구조에 적합하다.
      (테스트 자료 생성 → 테스트 자료 조작 → 결과 확인)
    • 도메인에 특화된 테스트 언어 (p.161)
      • 시스템 조작 API를 사용하는 대신 API 위에 함수와 유틸리티 구현 후 이를 사용하므로 테스트 코드를 짜기도 읽기도 쉬워진다.
      • 이렇게 구현한 함수와 유틸리티는 테스트 코드에서 사용하는 특수 API가 되며, 추후 독자를 위한 테스트 언어다.
      • 숙련된 개발자라면 자기 코드를 좀 더 간결하고 표현력이 풍부한 코드로 리팩토링해야 마땅하다.
    • 이중 표준 (p.161)
      • 테스트 코드는 간결하고 표현력이 풍부해야 하지만, 실제 코드만큼 효율적인 필요는 없다.
        (실제 환경과 테스트 환경은 요구사항이 다르기 때문)
      • 대개 메모리나 CPU 효율과 관련 있는 경우 실제 환경에서는 절대로 안되지만 테스트 환경에서는 전혀 문제 없는 방식이 있다.
  • 테스트 당 Assert 하나 (p.164)
    • 테스트 코드 당 assert 문을 단 하나만 사용하면 결론이 하나라서 코드를 이해하기 쉽다.
    • 하지만, 위 규칙을 지키기 위해 테스트를 분리하면 중복되는 코드가 많아진다.
      • 이를 해결하기 위해 TEMPLATE METHOD 패턴 또는 @Before 함수를 사용할 수 있으나 배보다 배꼽이 더 크다.
    • 단일 assert 문 규칙을 반드시 지키기 보다는 assert 문 개수는 최대한 줄이되 필요하다면 여러 개를 사용한다.
    • 테스트 당 개념 하나 (p.166)
      • 여러 개념을 연속으로 테스트하는 긴 함수는 피한다.
    • 가장 좋은 규칙은 개념 당 assert 문 최소화테스트 함수 하나는 개념 하나만 테스트하라이다.
  • F.I.R.S.T. (p.167)
    • F (Fast) : 테스트는 빨리 돌아야 한다.
      • 테스트가 느리면 자주 돌릴 엄두가 나지 않고, 결국 코드를 마음껏 정리하지도 못하여 코드 품질이 망가지기 시작한다.
    • I (Independent) : 각 테스트는 서로 의존하면 안 된다.
      • 한 테스트가 다음 테스트가 실행될 환경을 준비해서는 안된다.
      • 각 테스트는 독립적으로, 어떤 순서로 실행해도 괜찮아야 한다.
      • 테스트가 서로 의존할 경우, 하나가 실패할 때 연달아 실패하므로 원인을 찾기 어려워지며 후반 테스트가 찾아내야 할 결함이 숨겨진다.
    • R (Repeatable) : 테스트는 어던 환경에서도 반복 가능해야 한다.
      • QA 환경이나 테스트가 돌아가지 않는 환경이 하나라도 있다면 테스트가 실패한 이유를 둘러댈 변명이 생긴다.
      • 그리고 환경이 지원되지 않기 때문에 테스트를 수행하지 못하는 상황에 직면한다.
    • S (Self-Validating) : 테스트는 bool 값으로 결과를 내야 한다.
      • 성공 아니면 실패로 결과가 나와야지 성공 여부를 알기 위해 로그 파일을 읽게 해서는 안 된다.
      • 테스트 스스로 성공과 실패를 가늠하지 않는다면 판단은 주관적이게 되고, 지루한 수작업 평가가 필요하게 된다.
    • T (Timely) : 테스트는 적시에 작성해야 한다.
      • 단위 테스트는 테스트하려는 실제 코드를 구현하기 직전에 구현한다.
      • 실제 코드를 구현한 이후에 테스트 코드를 만들면 구현하기도 어려울 뿐더러 테스트하기 어렵다고 판단할 수도 있다.
  • 결론 (p.168)
    • 테스트 코드는 실제 코드만큼이나 프로젝트 건강에 중요하다.
    • 테스트 코드는 지속적으로 깨끗하게 관리해야 한다.
      • 표현력을 높이고 간결하게 정리하기
      • 테스트 API를 구현해 DSL을 만들기
    • 테스트 코드가 망가지면 실제 코드도 망가지기 쉽다.

🤔 소감 및 생각

  • 테스트 코드가 중요하다는 것은 어느정도 알고 있었지만 이번 챕터를 다 읽고 나니 얼마나 중요하게 생각해야 하는지 절감하게 되었다. 기존에 구현된 코드에 대하여 테스트 코드를 작성하고자 하였을 때 왜 쉽지 않았는지 이제서야 납득이 되었다. 기능 구현 전에 테스트 코드를 작성하고, 이후에 코드가 변함에 따라 함께 변해왔어야 했지만 그렇지 못하고 한참 후에야 테스트 코드를 생성했기 때문이다. 기존에 TDD 기반으로 작성되지 않은 코드는 어떻게 유지보수를 진행하며 테스트 코드를 작성할 수 있을지 고민해봐야 할 것 같다.
  • 그리고 TDD를 하게 된지 그렇게 오랜 시간이 지난 것은 아니라 부족하지만 이중 표준 절에 나오는 코드는 납득하기 어려웠다.
    (저렇게 테스트 코드를 작성하고 코드 리뷰 올리면 의견이 많이 달릴 것 같은 느낌적인 느낌)

🔍 새롭게 또는 다시 알게 된 내용

  • BUILD-OPERATE-CHECK 패턴 : 테스트 코드 작성 시 사용되는 패턴
    • BUILD : 테스트 자료 생성
    • OPERATE : 테스트 자료 조작
    • CHECK : 결과값 확인

0개의 댓글