[임베디드 C를 윈한 TDD] 6장 좋아 하지만…

3 minute read

개요

본 장에서는 서적의 6장 내용을 정리하였습니다.

TDD를 처음 하면 몇몇 걱정이 생기게 됩니다. 이번 장에서는 TDD를 하면서 드는 의문에 대해 설명해주고 있습니다.

우린 시간이 없어요

개발을 하다보면 시간에 시간이 촉박하기 마련입니다. Led 드라이버를 보면 제품 코드보다 테스트 코드가 더 깁니다.

TDD를 실천하는 많은 사람들은 TDD가 업무 속도를 향상시킨다고 합니다. 속도 향상은 미래의 디버그 시간이 줄어들고, 실행 가능한 문서 역할을 하는 테스트 코드를 통해 더 깔끔하게 유지되기 때문입니다.

만약 TDD 가 시간이 더 걸린다면 어떨까요? 하지만 개발 소요시간 외에도 여러가지 비용이 있습니다. 예를 들면 고객 불만족, 판매 손실, 보증 수리, 결함 관리, 고객 서비스 등등… 이 있겠습니다. 시간을 조금 더 쓰더라도 더 적은 결함을 가진 제품을 내놓는 것이 더 가치가 있을 것입니다.

TDD를 하기 위해 시간을 찾으려면 먼저 현재 일하는 방식을 들여다봐야 할 것입니다.

수동 테스트

만약 현재 수동으로 단위 테스트를 하고 있다면, 이 시간의 일부를 TDD에 활용하도록 하는 것이 좋습니다. 레거시 환경에서 작업하고 있다면 수동 테스트를 완전 배제할 수는 없지만, 새로운 코드를 TDD로 개발하거나, 테스트되지 않은 레거시 코드의 일부에 대해 테스트를 작성할 수도 있을 것입니다.

수동 테스트의 초기 투자 테스트는 자동화보다 적을지 모르지만, 지속적이지 않습니다. 미래로 가면 거의 제로에 가까울 수 있습니다. 필요한 테스트를 재수행하지 않으면 테스트가 빨리 끝나서 좋겠지만, 향후 버그에 대한 비용은 감수해야 할 것입니다.

지속적인 테스트 하니스

우리는 가끔 새로 작성하는 코드에 대해서 테스트 main() 과 테스트 스텁을 몇몇 작성해 보았을 것입니다. 이는 자체적인 테스트 하니스를 만든 것으로 볼 수 있습니다.

이러한 테스트들은 매우 유익합니다. 코드의 품질이 향상되며, 더욱 더 잘 동작하는 코드를 제품에 통합시킬 수 있습니다.

하지만 코드가 통합되었을 때 기존의 테스트들이 방치되는 경우가 많은데, 이를 테스트 하니스에 넣어 지속적으로 유지하는 것이 좋습니다.

한 스텝씩 실행하는 단위 테스트

또 다른 수동 단위 테스트 방법으로 디버거를 사용해서 대상 코드를 한 스텝씩 실행하는 것입니다. 이 방법은 느리기도 하며, 반복하기 힘든 작업입니다.

이러한 테스트의 유효 수명은 위에서 언급한 main() 보다 짧습니다. 일부가 변경되면 이전의 테스트는 무용지물이 될 수 있습니다. 그러면 결국 처음부터 다시 테스트를 하게 됩니다. 수동 테스트에 드는 노력은 시간이 지나면 점점 증가하게 됩니다.

만약 시간이 없어서 모든 테스트를 할 수 없다면 버그가 발생하고, 향후에 드는 노력도 증가합니다.

단위 테스트에 들인 비용은 어디로 가는가?

TDD를 하지 않았다면 대부분 수동 테스트를 하거나 main() 함수 로 테스트를 할 것입니다. 이러한 활동들은 실행 비용은 엄청나지만, 돌려받는 것은 극히 한정적입니다.

이러한 방법들은 단위테스트에 직접 비용을 들이고, 디버깅을 하면서 간접 비용이 듭니다. 현재 단위 테스트에 들이는 비용 중 일부를 TDD에 들이는 것을 고려하는 것이 좋습니다. TDD에서는 변경이 있을 때 마다 테스트를 실행하고, 코드와 함께 테스트도 발전하기 때문에 투자에 대한 이득을 훨씬 많이 얻게 됩니다.

코드 작성 후에 테스트를 작성하면 왜 안되나?

일반적으로는 개발 후에 테스트를 작성합니다. 이를 개발 후 테스트 (Test-After Development) 라고 합니다. 테스트를 나중에 작성하는 것도 효과가 있긴 하지만, 테스트를 주도로 코드를 작성하는 것에는 미치지 못합니다.

다음은 TAD로는 얻을 수 없는 TDD 의 이득에 대한 몇가지 예입니다.

  • TDD는 설계에 영향을 미치게 된다. 테스트를 나중에 작성하는 경우에는 TDD가 설계에 미치는 긍정적 효과를 얻을 수 없다. TDD는 더 나은 API와 낮은 결합도, 높은 응집도를 가져온다.
  • TDD는 결함을 방지한다. 작은 실수를 하면 TDD는 바로 그것을 찾아낸다. 테스트를 나중에 작성할 때도 많은 실수를 찾아낼 수 있겠지만, TDD라면 발견할 수 있는 것들의 일부는 놓칠 수 있다. 이런 실수들은 결국 여러분의 버그 데이터베이스를 채울 것이다.
  • 테스트를 나중에 작성하면 테스트 실패의 근본 원인을 찾는 데 소중한 시간을 낭비하게 된다. 하지만 TDD에서는 보통 근본 원인이 명백하게 드러난다.
  • TDD가 더 엄격하고 테스트 커버리지도 높다. 테스트 커버리지가 TDD의 목적 은 아니지만 테스트를 나중에 작성하면 테스트 커버리지가 낮아진다.

테스트를 유지보수해야 할 것이다

테스트가 없다면 유지보수할 필요도 없겠지만, 대신 지루한 수동 테스트를 반복해야만 할 것입니다. 테스트로 인해 얻게 되는 가치는 유지 보수에 들어가는 노력을 보상할 것입니다.

TDD 와 테스트 케이스 설계 기술을 익히고 나면 유지보수 하는 일은 어렵지 않을 것입니다.

단위 테스트가 모든 버그를 찾아낼 수는 없다

사실이긴 하지만, 이것이 TDD를 하지 않을 이유는 아닙니다. TDD는 코드 한줄한줄이 원하는대로 동작한다는 것을 보장할 수 있도록 도와줍니다.

여전히 통합 테스트, 인수 테스트, 부하 테스트 등이 필요합니다.

TDD로 인해 문제들이 많이 제거되며, 상위 수준의 테스트에 걸맞는 문제를 찾게 됩니다. 단위 테스트는 변경이 일어날 때에 효과가 드러나게 됩니다. TDD 단위 테스트를 통해 변경이 정확하게 의도한대로 동작하는지를 검증할 수 있습니다.

사소한 실수가 크나큰 버그로 다가올 수 있습니다. 실수가 작든 크든 실수 방지를 위해서 TDD는 아주 효과적입니다.

빌드가 오래 걸린다

빌드 시간이 오래 걸린다면 증분 빌드 시간을 줄이기 위해 단위 테스트 빌드를 여러 개로 나눌 필요가 있습니다. 각 테스트를 필요한 모듈로 이동한 뒤 병렬처리를 통해 빌드를 수행하면 빌드 시간을 단축할 수 있습니다.

기존 코드는 어떻게?

아마 대부분의 개발자들은 현업에서 개발하고 있는 기존 코드들이 있을 것입니다. 또한 대부분은 자동화 테스트가 적거나 없을것입니다. 아마 이 상황에서 TDD를 바로 적용하기는 쉽지 않습니다. 이 경우 개발을 멈추면서 모든 테스트를 작성하는 것은 실용적이지 않을 것입니다.

기존 제품에 테스트를 추가하면서 TDD를 적용해나가는 기법들은 아래와 같습니다.

  • 새로운 함수에 모듈과 TDD 사용하기
  • 기존 코드를 변경할 때 테스트 추가하기
  • 버그를 수정할 때 테스트 추가하기
  • 미래를 위한 전략적 테스트들에 투자하기

이 주제는 13장인 레거시 코드에 테스트 추가하기 에서 상세하게 다룰 예정입니다.

Leave a comment