본문 바로가기
Dev/테스트 코드

좋은 테스트의 조건 - 유지보수성

by 싯벨트 2025. 3. 27.
728x90

유지보수성이 좋지 않은 테스트는 프로젝트 일정을 지연시킵니다. 유지 보수성이 테스트를 얼마나 자주 변경해야 하는지 가늠하는 척도라면 그 횟수를 최소화하는 것이 중요합니다. 유지 보수성 측정을 시작한다면, 일정 기간 동안 발생하는 거짓 실패 횟수와 그 원인을 분석하는 것부터 시도해볼 수 있습니다.

테스트 실패로 코드 변경

실제 실패(true failure)는 테스트가 프로덕션 코드에서 버그를 발견하여 실패하는 경우이고, 거짓 실패(false failure)는 다른 이유로 테스트가 실패하는 경우입니다. 거짓 실패를 만드는 케이스들을 살펴보겠습니다.

프로덕션 코드에 새로운 기능 추가

기댓값 등이 변경된 요구사항과 맞는지 살펴보고 효하지 않은 테스트는 삭제해야 합니다.

프로덕선 코드의 API 변경

함수나 객체를 사용하는 방식이 달라진다면 테스트 코드가 변경될 가능성이 높습니다. 생성자에 매개변수가 추가 또는 삭제되거나, 자료형이 변경되거나, 함수 시그니처가 변경되는 등의 변경이 있을 수 있고, 이와 관련된 테스트는 모두 수정을 해줘야 할 수도 있습니다.

팩토리 함수 사용

이러한 상황에 대처하여 유지 보수성을 높이려면 테스트할 코드의 생성 과정을 분리하거나 추상화해야 합니다. 팩토리 함수를 사용하여 객체 생성 과정을 분리하면, 변경이 발생하더라도 팩토리 함수만 수정함으로써 대응할 수 있게 됩니다.

서로 영향을 주는 테스트

같은 기능을 검증할지라도 각각의 테스트는 서로 독립적이어야 합니다. 순서가 정해졌다면 이를 제거해주어야 하며, 헬퍼 함수를 활용하면 해결이 되는 경우가 많습니다. 또한 코드 내에서 공유하는 변수나 함수 등의 자원이 있을 때는 beforeEach(), afterEach() 함수를 사용하여 테스트 실행 전/후에 리셋을 해줍니다.

유지 보수성을 높이는 리팩터링 방법

private, protected 메서드 사용하지 않기

private, protected 메서드는 내부 동작을 의미합니다. 그래서 이들을 호출하는 외부 동작인 public 메서드가 반드시 존재하기 마련입니다. 테스트에서 중요한 것은 시스템의 외부 동작, 즉 public 메서드가 올바르게 작동하는지 확인하는 것입니다. 만약 private 메서드를 테스트해야 한다면 이는 추상화가 부족하다는 신호로, 해당 메서드를 public으로 만들거나 별도의 클래스로 분리해야 한다는 것을 의미합니다.

TDD에서는 먼저 public 메서드를 테스트하고, 이를 작은 private 메서드를 호출하도록 리팩터링하는 과정을 거칩니다.

메서드를 public으로 만들기

메서드를 public으로 만든다는 것은 그 메서드가 일정하게 동작하거나 중요한 역할이라는 것을 명확하게 나타냅니다.

메서드를 새로운 클래스나 모듈로 분리

메서드에 독립적으로 동작할 수 있는 로직이 많이 포함되어 있거나, 해당 메서드와 관련된 특정 상태값을 사용한다면 그것만 테스트할 수 있도록, 새로운 클래스나 모듈로 분리하는 것도 좋습니다.

테스트에서도 DRY 원칙 고수

헬퍼함수를 사용하여 중복을 최소화할 수 있습니다.

초기화 함수 사용하지 않기

beforeEach() 함수는 초기화 함수로, 객체를 초기화할 때만 유용합니다. 그리고 모든 테스트가 영향을 받을 때만 사용해야 하며, 목이나 가짜 객체를 만들거나 길고 어려운 코드를 포함해선 안 됩니다.

매개변수화된 테스트로 중복 코드 제거

초기화 함수 대신 test.each(), it.each() 함수를 사용하여 매개변수화된 테스트를 사용할 수 있습니다.

과잉 명세된 테스트

테스트는 외부 동작을 확인하면 됩니다. 내부 동작까지 검증하는 것은 과잉 명세된 테스트입니다. 다음과 같은 경우, 테스트가 과잉 명세되었다고 볼 수 있습니다.

  • 테스트가 객체의 내부 상태만 검증
  • 테스트가 목을 여러 개 만들어 사용
  • 테스트가 스텁을 목처럼 사용
  • 테스트가 필요하지 않은데도 특정 실행 순서나 정확한 문자열 비교를 포함

참고자료