TDD

[TDD] TDD가 실패하는 이유

y0ngha 2021. 12. 29. 21:29

TDD를 많이 적용하려고 한다.

하지만, 실제로 업무에 적용을 하기까지는 많은 시간이 필요하며, 그 많은 시간을 들여서도 적용을 했을 때 실패하는 케이스가 대부분이다.

그렇다면 TDD를 왜 실패할까?

TDD를 설계방법론으로 이해하고, 설계를 진행하는데 사용하고 있다.

TDD가 설계방법론이라면, 우리는 TDD를 통해 좋은 설계를 얻을 수 있어야한다.

하지만 TDD는 아래의 특징을 갖고 있다.

  • TDD는 높은 응집을 유도하지 않는다.
  • TDD는 단일 책임 원칙(SRP)과 인터페이스 분리 원칙(ISP) 위배에 어떤 신호도 주지 않는다.
  • TDD는 인터페이스 일관성을 도출하지 않는다.
  • TDD의 리팩토링 단계는 좋은 구조를 갖게 하도록 안내하지 않으며 또한 강제하지 않고 있다.

위 4가지의 내용으로 보았을 때 TDD는 설계방법론이 아니라는 것을 증명해주고 있다.

물론 그렇다고 해서 TDD가 아예 설계에 영향을 안미치는 것은 아니다.

강한 결합과, 의존성 역전 원칙(DIP) 위배를 경고하고 불명확한 설계 지점을 안내해주기도 한다.

하지만 이러한 특성을 이용해 전적으로 TDD만 믿고 설계를 진행했다가는 테스트 하기만 좋은 안좋은 코드가 만들어지게 된다.

코드가 이루고자 하는 가치나 기능을 테스트 하지 않고, 그 기능을 어떻게 구현하고 있는지에 대해 테스트 코드를 작성하고 있다.

이는 테스트 케이스들이 구현체와 결합도가 높아지는 것을 의미하며, 결국 구현체를 리팩토링하게 되었을 때 테스트코드는 모두 깨지고 말것이다.

테스트 케이스가 구현체와 높은 결합도를 유지하고 있는 안좋은 케이스
내부 구현체들을 리팩토링하게 된다면(다양한 모형에서 네모로 모두 바뀜)

 

펑.

위 그림의 문제점은, 테스트 케이스가 내부를 아주 상세하게 잘 알고있으며, 내부 구현체가 변경됨에 따라 테스트 케이스들 또한 영향이 가게 된다.

내부 비즈니스 로직이 변경되었을 때 테스트케이스를 다시 작성해야한다면 이는 상당한 비용이 들 것이다.

이러한 상황이 발생될 수 있는 이유는 Mock을 많이 사용해서 발생하는 경우도 있다.

(내부 함수를 mocking하여 테스트를 진행할 때 내부 함수가 변경되게 된다면 테스트케이스가 모두 깨지는 상황이 발생된다.)

 

implementation을 바라보게 하는 것이 아닌, interface를 바라보고 테스트 코드를 작성해야 한다.


내부 구현체가 리팩토링 되도 테스트 케이스는 깨지지 않는다.

 

그러면 대체 어디까지가 구현체고, 어디까지가 인터페이스일까?

- TDD의 창시자인 켄트백도 이 부분은 어렵다고 했다.

개인적인 생각으로는 테스트코드 내부에서 구현한 함수들을 사용하지 않는 선에서 작성을 해야하는 것이 아닌가 생각된다.

왜냐하면 TDD는 테스트 코드임과 동시에 해당 모듈이 어떤 동작을 할 지 알려주는 가이드 문서의 역할도 하기 때문이다.

억지로 TDD를 적용하고 있다.

TDD를 사용할 때 팀이 준비가 안되어있다면, 개인이 준비가 안되어있다면 적용되어서는 안된다.

준비가 되어있지 않는 상태에서 적용을 하게 될 경우 테스트 코드로 인해 정상적인 업무 또한 힘들어질 것이다.

 

또한 모든 코드를 TDD로 테스트 하려고 하지 말도록 하자.

테스트 코드를 통해 안정적으로 진행할 수 있는 코드라면 작성하는 것이 좋은데, 그렇지 않을 경우 안하는것이 좋다.

 

TDD를 사용할 때에는 "요구사항 분석" → "Test Code 작성" → "App 작성" 으로 전략을 짜는게 이상적이다.

테스트를 단위별로 끊게 되면 "Component Render" → "Action" → "Check Result" 가 된다.

 

참고자료)

- 피카의 TDD와 단위테스트(테코톡) [발표 보러가기]

- [OKKYCON: 2018] 이규원 - 당신들의 TDD가 실패하는 이유  [발표 보러가기]