본문 바로가기
Software Engineering

테스트 코드 그게 뭔데? 중요한거야?(feat. TDD)

by nak_honest 2023. 8. 24.

1학기에 소프트웨어 공학 수업을 들으며 테스트 코드를 짜는게 중요하다는 말은 많이 들어보았다. 하지만 실제로 개발을 하면서 테스트 코드를 짜본적이 한번도 없다. 이 글을 통해 테스트 코드 작성의 중요성을 이해하고, 작성에 대한 동기를 얻어보자!!

먼저는 장점에 대해 조금더 자세하게 살펴보기 전에 아주 살짝 TDD(Test-Driven Development)가 무엇인지 알아보자.
TDD가 뭔지 처음 들어본다면 이것이 무엇인지 알아 본 뒤에 이 글을 읽어보는 걸 추천한다!
이 글의 내용이 결국 TDD의 장점에 대한 내용이기 때문이다.

TDD는 테스팅과 코드 개발을 혼합시키는(interleaved) 개발 접근법이다. 즉 개발을 하면서 테스팅이 동시에 일어나는 접근법을 말한다.

이때 중요한 점은 테스트 코드가 프로덕션 코드보다 먼저 작성되어야 한다는 것이다.  
즉 새로운 기능이 구현되기 전에 해당 기능에 대한 테스트를 먼저 작성해야 한다.  

그리고 모든 변화가 생길때마다 프로그램은 테스트 되어야 한다. 테스팅을 자동화 하고, 개발 프로세스의 중심에 테스팅을 둠으로써 모든 테스트를 통과하기 전에는 개발을 진행할 수 없도록한다.  




 

그렇다면 이제 테스트 코드의 장점을 알아보자.

테스트 코드를 왜 작성하는 것일까?

이는 테스트 코드를 작성했을때의 장점을 보면 알수 있다.

  1. 디버깅 비용이 절감된다.
  2. 기능 추가 및 수정으로 인한 부작용을 줄일 수 있다.
  3. 테스트 코드를 작성하는 것이 오히려 개발에 대한 시간과 비용을 절감시켜 준다.
  4. 테스트 코드 자체가 코드를 설명하는 문서가 된다.
  5. 비정상적이고 예상할 수 없는 상황을 사전에 대비할 수 있다.

 

디버깅 비용이 절감된다.

먼저 결함이 아예 없는 소프트웨어란 존재할 수 없다. 아무리 설계를 잘하고 좋은 코드를 작성하여도 소프트웨어는 그 자체로 결함을 가지고 있을 수밖에 없다. 또한 소프트웨어는 변화에 불가피하기 때문에 이러한 변화에 대응하면서 소프트웨어는 더 많은 결함이 발생할 수 밖에 없다.

일단 테스트의 목적 중 하나는 이러한 버그와 결함을 찾는 것이다. 따라서 이러한 테스트 코드를 작성하면 더 빠르게 결함을 찾을 수 있고, 이를 통해 결함을 빠르게 해결할 수 있다. 그리고 TDD를 따르면 기능을 추가할때마다 테스트를 하기때문에, 테스트가 실패하면 어디서 결함이 발생했는지를 빠르게 찾을 수 있다.

이전에 구현한 기능들마다 테스트가 계속해서 이루어졌기 때문에, 새로운 기능으로 인한 결함은 새로운 기능에 있을 확률이 높기 때문이다. 따라서 테스트가 실패하여서 문제가 어디에 있는지 정확하게 찾아야 할때 간단한 디버깅을 통해 찾을 수 있다.

여기서 이전에 구현한 기능들이 테스트에 통과되었다고 전혀 결함이 없는 것은 아니라는 것에 주의하자. 완벽한 테스팅이란 없다.

"테스팅은 오류의 부재가 아닌 오류의 존재만 보일 수 있다."



기능 추가 및 수정으로 인한 부작용을 줄일 수 있다.

코드가 변경되다 보면 그 변경으로 인해 소프트웨어에 결함이 발생할 수 있다. 그리고 그 변경으로 인해 이전에 잘 동작하던 부분에서 결함이 발생하는 경우도 많다. 이때 기존 기능에 대한 테스트 코드가 있다면 이 변경으로 인해 결함이 발생하는지를 빠르게 파악할 수 있다.

이를 회귀 테스팅이라고 하는데 이는 TDD의 중요한 장점 중 하나이다. 회귀 테스팅은 시스템의 변경사항이 새로운 버그를 초래하거나 기존 코드를 손상시키지 않는지 테스팅 하는 것이다. 즉 새로운 기능이나 변화를 가한 후에 이전에 만든 것들이 잘 작동하는지 테스트하는 것인데, 이 테스트가 원래는 비용이 비싸고 수작업으로 테스트 할것을 하나하나 작성해야 한다.

하지만 TDD를 적용하면 전체 테스트가 자동화 되어 있기 때문에 회귀 테스팅의 비용이 극적으로 감소된다. 프로그램이 변경될때마다 이전에 작성했던 모든 테스트가 재실행되고, 이 테스트들이 모두 통과되어야만 이 변화가 받아들여지기 때문에 안정적으로 변화를 받아들일 수 있게 된다.



테스트 코드를 작성하는 것이 오히려 개발에 대한 시간과 비용을 절감시켜 준다.

처음에는 테스트 코드를 작성하는 것이 귀찮고 개발 프로세스를 지연시키는 것이라는 생각이 들수도 있다. 하지만 장기적으로 보았을때에는 오히려 개발 비용을 아껴준다.

소프트웨어에서 가장 많은 비용이 드는 곳은 어디일까?
-> 그것은 바로 유지보수 비용이다.

소프트웨어를 사용하면서 계속해서 버그나 결함이 발생하고, 소프트웨어는 주변 환경, 비즈니스 등의 변화에 영향을 받을 수 밖에 없다. 소비자의 요구사항은 중간에 변경이 일어날 수 있고, 소프트웨어에 적용되는 법이 바뀌기도 한다.

하지만 테스트 코드를 매 기능마다 작성하고, 실행해서 통과 시키면 이러한 유지보수 비용이 매우 감소하게 된다. 먼저는 앞에서 설명한대로 결함과 버그가 발생했을때 테스트를 통해 어디서 발생하는지를 소프트웨어 배포 전에 빠르게 발견할 수 있고, 또한 어디서 발생했는지도 쉽게 알아챌 수 있다.

 

뿐만 아니라 변화에 유연한 좋은 코드를 만드는데에도 많은 도움을 준다. 즉 코드의 품질이 향상된다. 이는 리팩토링과도 관련이 있는데, 만약 리팩토링 시 테스트 코드가 존재하지 않는다면 리팩토링을 하고나서 기존 기능과 똑같이 잘 작동하는지 확인하기가 어렵다. 리팩토링은 기존의 레거시 코드를 변경하여 변화에 유연하도록 만드는 것인데, 만약 이 리팩토링으로 인하여 기존 기능이 잘 동작하지 않게 된다면 오히려 리팩토링으로 인한 손해 비용이 더 커지게 된다.

하지만 테스트 코드가 존재한다면 리팩토링을 한 뒤에 기존 기능과 똑같이 잘 작동하는지를 확인할 수 있고, 큰 안정감 속에서 리팩토링을 진행할 수 있다. 이를 통해 효율적으로 리팩토링을 하여 코드를 개선해 나가기 쉬워지게 된다.

 

물론 유지보수 측면 뿐만 아니라 개발 초기 단계에 요구사항을 분석하고, 소프트웨어를 설계하는데에도 도움을 준다. 기능을 구현하기 전에 테스트 코드를 먼저 작성해야 하는데, 그렇게 하려면 자연스럽게 해당 기능이나 요구사항 등이 잘 분석되어 있어야 하기 때문이다. 즉 테스트를 하기 위해서 어떤 기능을 수행하는지, 어떤 역할을 맡고 있는지 더 명확하게 파악할 수 있게되고 이는 품질이 좋은 소프트웨어를 설계하는데 도움을 준다.

그리고 좋은 코드는 테스트하기 쉽다는 특징이 있다. 즉 테스트하기 어려운 코드라면 나쁜 smell을 내는 코드일 확률이 높다는 것이다. 이에 대한 부분은 '향로'님의 글을 첨부해 본다!

 

https://jojoldu.tistory.com/674

 

1. 테스트하기 좋은 코드 - 테스트하기 어려운 코드

팀 분들과 함께 NextStep - 이펙티브 코틀린 강좌를 수강하고 있다. 최근에 과제 회고를 처음 진행했는데, 이때 나온 주제가 테스트 하기 좋은 코드였다. 이 주제는 사실 이미 너무 많이 회자된 주

jojoldu.tistory.com

 

 

테스트 코드 자체가 코드를 설명하는 문서가 된다.

테스트를 읽는 것은 코드를 이해하는데 도움이 된다. 즉 문서로서의 역할이 가능하다.

테스트 코드는 해당 코드가 어떤 기능을 해야하는지, 어떻게 동작 해야하는지를 알려준다. 따라서 테스트 코드를 통해 코드의 예상 동작을 명확하게 확인할 수 있다.

테스트 코드는 기능 코드의 가장 가까운 곳에서 가장 비슷한 언어로 쓰인 명세화이다. 테스트 코드만 잘 작성했다면 작성한 메소드, 클래스, 인터페이스 등의 코드가 어떤 역할과 기능을 하는지 쉽게 파악할 수 있게 된다.



비정상적이고 예상할 수 없는 상황을 사전에 대비할 수 있다.

먼저 테스팅은 크게 두가지 유형의 테스팅으로 나눌 수 있다.

  • validation testing : 시스템이 예상대로 사용되었을 때에 대한 테스트 케이스를 돌려서 시스템이 정확하게 수행되는지를 확인하는 것이다. 즉 정상적으로 돌아가는지를 확인하는 테스트이다.
  • defect testing : 이 테스트는 결함이 드러나도록 테스트 케이스를 디자인 한다. 따라서 의도적으로 모호하고 비정상적인 데이터를 넣을 수 있고, 정상적으로 시스템을 사용하지 않았을 때에 대한 동작에 대해서 테스트할 수 있다.

여기서 defect testing을 주의깊게 보자. 테스트는 정상적으로 동작되는지에 대해서만 확인하는 것이 아니다.
비정상적이고 예외적인 부분에 대해서도 테스트를 해야한다.

왜냐하면 사용자가(심지어는 함께 협업하는 다른 개발자가) 언제나 프로그램을 정상적으로만 사용한다는 보장이 없기 때문이다. 또한 굳이 사람에 의해서가 아니더라도 에러를 발생시키는 비정상적인 데이터와 상황은 수없이 많다.

 

따라서 이를 소프트웨어를 배포하기 전에 비정상적인 입력이나 예외 상황이 적절하게 처리되고, 시스템 컴포넌트를 망가뜨리지 않는지 검사해야 한다.
경험적으로 문제를 일으킬 만한 것들을 입력으로 넣는 테스트 코드를 작성하여서 비정상적이고 예외 상황에 대해서 사전에 파악해야 한다.

만약 사전에 테스트하지 않으면, 소프트웨어가 배포 되고 나서 예외 상황에 대해 시스템에 에러가 발생하게 될테고 이를 수정하는데에는 더 큰 비용이 발생하게 된다. 따라서 테스팅을 통해 미리 예외 상황에 대한 시스템의 동작을 확인하는 것은 매우 중요하다.



 

이렇게 테스트 코드를 작성하는 것이 왜 중요한지 배웠고, TDD의 장점에 대해서도 배웠다.
앞으로는 테스트 코드를 작성하는 것을 귀찮아하지 말고 몸에 습관이 배이도록 하자!!

 

출처