TDD와 단위테스트

Sheryl Yun·2022년 4월 3일
0

개발 상식 쌓기

목록 보기
1/11
post-thumbnail

TDD란?

Test-Driven Development 의 약자
테스트 코드를 먼저 만들고 실제 프로덕션 코드는 나중에 만드는 개발 방법

기존의 개발 프로세스

설계를 가장 먼저 하고, 프로덕션 코드 개발 이후 맨 마지막에 테스트 작성

TDD 개발 프로세스

테스트 코드를 가장 먼저 작성하고, 이후에 설계 및 프로덕션 개발 진행

TDD 개발 사이클

Red, Green, Refactor 라고도 부른다.

Red (실패 코드)

실패하는 테스트를 먼저 구현해서 테스트를 실패한다.

Green (성공 코드)

이후 테스트를 성공시키는 프로덕션 코드를 작성한다.

Refactor (리팩토링)

마지막에 프로덕션 코드와 테스트 코드를 모두 리팩토링한다.

TDD가 만들어진 이유

테스트 코드 자체의 특징

  • 수정에 대한 두려움을 줄여줘서 리팩토링이 편해진다.
  • 디버깅하는 시간을 줄여준다.
  • '동작하는 문서' 역할을 한다. (실제 코드의 구현 상세를 문서화한 코드)

TDD만의 장점

  1. 테스트 커버리지가 높아진다.
    테스트 코드를 먼저 작성하고 이후 프로덕션 코드를 거기에 맞추는 식이기 때문에 자연스럽게 테스트 커버리지가 높아진다.

🙋‍♀️ Question

나중에 테스트 코드를 작성해도 테스트 커버리지는 높일 수 있는데 뭐가 다른걸까?

테스트 코드를 나중에 작성하게 되면, 사람의 특성상 테스트 코드 작성을 잊거나 뒤로 미루는 경우가 발생한다. 결국 프로그램의 안정성을 높일 수 있는 테스트 코드를 작성하지 않을 수도 있다. (기능 배포 여부에는 영향을 미치지 않는 부분이므로)

유의할 점: 테스트 커버리지가 높다고 해서 무조건 좋은 코드인 건 아니다!
=> ROI(Return On Investment, 투자수익률)의 관점에서 테스트 코드는 '비용'이기 때문

  1. 오버 엔지니어링을 방지할 수 있다.
    테스트 코드를 먼저 작성하면 이때 요구사항에 맞춘 코드를 어느 정도 작성하기 때문에 이후 세부 프로덕션 코드에서 정말 필요한 만큼만 코딩할 수 있다.

    오버 엔지니어링
    미래에 필요할 것 같은 구현을 지레짐작하여 불필요한 코드를 작성하는 것

  2. 설계에 대한 피드백이 빠르다.
    테스트 코드 작성 후 바로 설계를 진행하면 설계가 이상할 때 그 과정에서 바로 체크를 할 수 있다.
    => 테스트 코드를 작성할 때 복잡하고 잘못된 설계를 테스트 코드로 구현하려고 하면 새로운 테스트 코드를 작성하는 것 자체가 점점 더 어려워지기 때문이다.

결국 테스트 코드를 먼저 작성하고 개발을 한다는 것은
실제 프로덕션 개발로 넘어가기 전 제대로 된 '설계'를 가지고 시작한다는 말과 동일하다.

만약 TDD가 아닌 일반 개발 방식이라면, 설계 이후에 따로 확인하는 과정 없이 바로 프로덕션 개발로 진행하므로 개발이 모두 끝난 이후 테스트를 할 때 실제 구현 코드의 잘못된 점을 알게 되어 리팩토링 과정이 복잡해진다.

TDD에 대한 오해

TDD는 '설계방법론'이다?

만약 TDD가 설계방법론이라면 TDD를 통해 '좋은 설계'를 얻을 수 있어야 한다. 하지만..

=> 이 내용이 'TDD가 설계방법론이 아니다'라는 걸 증명해주고 있다. (??)


물론 TDD가 설계에 전혀 영향을 미치지 않는다는 건 아니다.

TDD는 강한 결합과 의존성 역전 원칙 위배를 경고하고,
불명확한 설계 지점을 발견해주기도 한다.

의존성 역전 원칙 (Dependency Inversion Principle)
객체는 저수준 모듈보다 고수준 모듈에 의존해야 한다는 원칙
고수준 모듈: 객체의 형태나 추상적 개념 (Interface)
저수준 모듈: 구현된 객체 (Implementation 안의 구현체)
즉, 객체는 객체보다 인터페이스에 의존해야 한다.
(= 가급적 객체의 상속은 인터페이스를 통해 이루어져야 한다)

하지만 TDD에 전적으로 지나치게 설계를 의존하게 된다면
테스트 하기에만 좋은, 결국 안 좋은 설계가 만들어진다.

TDD를 실패하는 이유

(이미지 첫 번째 항목 ??)

실패하는 테스트

Implementation 안에 있는 구현체들을 직접 테스트한다.
=> 이렇게 구현체 자체를 리팩토링하게 되면 테스트들이 깨질 수 있다.
(Implementation 안에 있는 구현체들은 서로 결합도를 가질 수 있기 때문에)

성공하는 테스트

구현체가 아닌 설계(Interface)를 테스트한다.
=> 가장 바깥쪽의 설계, 즉 Interface를 테스트하면
Implementation 안의 구현체를 아무리 리팩토링해도 테스트 케이스가 깨지지 않는다.


단위 테스트

먼저 프로그램 전반의 테스트 종류에 대해 알아보면 다음과 같다.

프로그램 테스트에는 크게 인수, 부합, 기능, 통합, 단위 테스트가 존재한다.

단위 테스트는 제일 작은 범위인 코드 단위를 테스트하며, 단위 테스트를 제외한 나머지 4개의 테스트들은 가장 기본적인 단위 테스트로부터 점점 더 범위를 넓혀나가며 테스트를 하게 된다.

단위 테스트의 특징

  1. 가장 작은 단위의 테스트 (일반적으로 메서드 레벨 테스트)
  2. 검증이 필요한 코드에 대해 테스트 케이스를 먼저 작성
  3. 테스트 코드 자체가 목적하는 코드의 완전성을 입증하므로 테스트 코드 자체만으로 가치가 있는 코드이다.

단위 테스트의 장점

1. 빠른 문제점 발견

각 단위가 정확하게 동작하는지 검사하고
문제가 발생 시 어느 부분이 잘못되었는지 빨리 확인할 수 있게 해 준다.
=> 프로그램의 안정성 증가

2. 쉬운 변경 및 수정

내부 구현체인 코드를 수정하거나 리팩토링해도 테스트 케이스가 깨지지 않는다. (=> 의존성 역전 원칙을 위배해도 괜찮다 ??)

3. 코드의 빠른 개선 (품질 향상)

하나의 단위 테스트가 너무 길어지거나 복잡해지면 프로덕션 코드에서 필히 잘못될 수 있는 부분이라고 본다.
따라서 하나의 테스트 메서드에서 너무 많은 기능을 수행한다고 생각되면 테스트 단계에서 바로 리팩토링을 진행할 수 있다.

4. 코드의 문서화

일명 '샘플 코드'라고 하며, 예외 상황, 용도, 의존 관계를 한눈에 파악 가능하다. (테스트 코드 = '동작하는 문서')

5. 프로덕션 코드와 테스트 코드 동기화

단위 테스트는 배포되는 코드와 일치하므로, 프로덕션 코드에 맞춰 항상 최신 상태로 유지된다.

좋은 단위 테스트 작성 법칙

일명 FIRST 법칙

F -- Fast (빠르게)

  • 테스트는 빨라야 한다.
  • 테스트가 느리면 자주 돌릴 엄두를 못 내는데, 그렇게 되면 문제를 빨리 찾아내서 고치지 못할 수도 있다.

I -- Independent (독립적으로)

  • 테스트는 서로 독립적이어야 한다.
  • 테스트가 서로 의존적이면, 하나가 실패할 때 나머지도 도미노처럼 실패하게 된다. 이는 후반 테스트가 찾아낼 수 있는 결함의 원인을 찾아내기 어려워지는 원인이 된다.

R -- Repeatable (반복 가능한)

  • 테스트는 어떤 환경에서도 반복 가능(실행 가능)해야 한다.
  • 실제 배포 환경이든, QA 환경이든, 심지어 버스 타고 집에 가는 길처럼 네트워크 연결이 안 된 환경에서도 테스트 실행이 가능해야 한다.
  • 이 점이 중요한 이유는 테스트가 돌아가지 않는 환경이 한 군데라도 있을 경우, 테스트가 실패하는 이유를 테스트 코드가 아닌 다른 상황적 변수에서 찾을 수 있기 때문이다.
  • 또 테스트가 돌아가지 않는 환경이 있다는 것은, 해당 환경에서 테스트 코드가 동작이 안 된다는 명확한 문제점을 의미한다.

S -- Self-Validating (자가 검증이 가능한)

  • 테스트는 Boolean 값으로 결과를 내야 한다. (=> 무조건 성공 아니면 실패를 반환해야)
  • 테스트가 스스로 성공과 실패를 가늠하지 못하면, 사람이 직접 테스트 결과를 주관적으로 판단해야 하는 비효율성이 발생한다.

T -- Timely (적시에, 적절한 타이밍에 작성)

  • 테스트는 항상 적절한 시기에 작성해야 한다.
  • 예를 들어, 단위 테스트는 반드시 테스트를 하려는 실제 코드를 구현하기 전에 작성해야 한다.
  • 만약 단위 테스트에서 실제 코드를 구현한 후에 테스트 코드를 짜면, 테스트하기 어려운 잘못된 프로덕션 코드가 작성된 것을 뒤늦게 발견할 수 있다.

출처: 테코톡 - 피카의 TDD와 단위테스트

profile
영어강사, 프론트엔드 개발자를 거쳐 데이터 분석가를 준비하고 있습니다 ─ 데이터분석 블로그: https://cherylog.tistory.com/

0개의 댓글