Unit Test (단위 테스트) 도입하기 - 1편

지금 부서의 역할이 사내에서 제품을 가지고 있는 팀들과 협업을 하면서 기존에 문제를 해결하고 사용자 관점에서 더 가치있는 제품을 항상 딜리버리 가능한 상태로 만드는 것을 목표로 하고 있다. 기존의 문제를 해결하는 방법으로 Agile의 Practice를 필요에 따라 활용하고 있으며, 특히 개발 Practice로는 TDD, Unit Test, Code Review, Pair Programming, CI/CD 자동화, Build Monitor 등의 프랙티스를 가져간다.

개발자로써 프로젝트를 진행하면서 TDD까지 전파하는 것은 정말 어려운 일이고, TDD까지 가기전에 Unit Test 작성하는 것을 우선적으로 전파하려고 하는 편이다. 테스트케이스 작성하는 방법을 체득화하고 그 이후에 TDD까지 이어가려고 하는데, TDD를 하기위해서 개발습관이나 사고방식이 함께 바껴야 하기 때문에 팀에 체득화 시키는 것은 항상 쉽지 않았다. TDD에 대해서는 할말이 너무 많지만, 이번 글은 Unit Test (단위 테스트) 주제로 2편에 나눠서 진행하고자 한다.

단위 테스트의 장점

테스트케이스를 꼼꼼하게 작성을 하면서 내가 변경한 부분이 어디에 영향을 끼치는지 쉽게 파악할 수 있었다. 그 덕분에 안심하고 리팩토링을 할 수 있는 점이 가장 좋았다. 단위 테스트를 하지 않는다면 제대로 수정했는지 확인될때까지 로컬에서 확인을 했을 것이다. 만약 오류가 발생하면 디버깅을 통해서 확인하는 작업을 반복했을 것이다.

이렇게 소요되는 시간을 포함해서 생각해본다면 “단위테스트 작성때문에 생산성이 떨어지는 것은 아니냐?” 라는 의문에 대해서 그래도 얻는 장점이 더 많다고 말할 수 있지 않을까 생각한다.

# 단위 테스트가 없다면 어떻게 작업을 했을까?

단위 테스트가 무엇이 좋았더냐?

  • 테스트케이스가 꼼꼼하게 작성되어 있다면, 개발과정 중에 미리 문제를 파악할 수 있다.
  • 코드변경시, 변경한 부분으로 인한 영향도를 쉽게 파악할 수 있다.
  • 코드 리팩토링을 안심하고 할 수 있다. 테스트케이스들은 내가 가입한 보험들 같다.
  • 테스트 자동화를 통해서 항상 딜리버리 가능한 제품을 만들 수 있다.
  • 새로운 입력이 팀에 합류했을때, 개발 스타일, 표준, 컨벤션등을 공유하기에 좋다.
  • 페어 프로그래밍을 할때, 테스트케이스 작성하고 개발하는 역할 핑퐁을 통해서 개발을 페어로 집중해서 진행할 수 있다.
    • TDD + Pair Programming을 한다면, 테스트케이스 작성한 사람의 설계를 공유하면서 소스 개발까지 이어질 수 있으므로 집중력있게 개발할 수 있다.

단위테스트에 대한 걱정

기존에 단위 테스트를 작성하지 않는 개발자분들과 프로젝트를 할때, 공통적으로 듣는 질문들이 있다. 질문에 대해서 하나씩 생각해보자. 아직 해보지 않았거나 어떻게 해야할지 모르기 때문에 생각보다 두려움이 커서 시도하기 어려울 수도 있다. 하지만 그 방법을 알거나 어떻게 하면 되는지 방법을 안다면 단위 테스트를 적용할 수 있을 것이다.

개발자들이 지금 일하고 있는 방식보다 더 편해질 수 있다는 것을 알게 된다면 다들 적용하리라 생각한다. 단지 경험이 없어서 확신이 없어서 적용하기 꺼려할 뿐, 한번 테스트로 인해서 도움을 받은 경험이 있다면 다음부터는 테스트케이스가 없는 곳에서 일하기가 더 힘들어 질 것이다.

Q. "기존에 레거시 코드는 어떻게 해야하나요?"

기존에 만들어진 코드에 모두 테스트 케이스를 만드는 것은 상당히 어렵다. 시간적인 여유가 있다면, 팀원들과 함께 작성하는 것을 시도해볼만하다.

하지만 이미 만들어진 코드의 규모가 크면 열정만으로는 다 커버하기가 쉽지 않다. 게다가 테스트 작성법을 잘 모르고 있다면 익숙해지기까지 시간이 오래 걸린다. 투자한 노력에 비해서 아직 커버할 부분이 많이 남아있는 것을 계속 확인하는 순간 지칠수도 있다.

  • 기존의 레거시 코드는 E2E 테스트로 커버하라.
  • 새로 개발하거나 변경하는 부분을 대상으로 우선적으로 단위 테스트를 시작하라.

그렇게 하면 시간은 오래걸릴 수 있지만, 점차적으로 단위 테스트를 늘려갈 수 있을 것이다. E2E 테스트 또한 기능이 복잡하거 나 중요한 기능부터 커버하기 시작하면 효율적으로 단위테스트 적용이 가능할 것이다.

# E2E Test

Q. "소스를 변경할때마다 단위테스트가 실패하면 유지보수 하는데 시간이 많이 들지 않나요?"

TDD(Test Driven Development, 테스트주도개발)의 라이프 사이클을 보면 테스트를 작성하고, 실패하는 것을 확인하고, 테스트가 통과하도록 고치고, 리팩토링을 통해서 코드품질을 향상하는 과정을 반복한다. 추가요건이 생기거나 리팩토링을 통해서 소스가 변경되어 단위 테스트가 실패하면 이를 고치는 것은 자연스러운 과정이다. 하지만 유지보수 쉬운 테스트케이스를 작성하는 것은 중요하다.

어떻게 하면 유지보수하기 쉬운 테스트케이스를 작성할 수 있을까?

  • 하나의 테스트에 하나의 기능만 검증하라.
    • SRP (Single Responsibility Principle, 단일책임의원칙)을 객체지향 개발에서 중요한 원칙으로 생각한다. 이는 테스트 작성에도 도움이 된다. 이를 유의하면서 테스트케이스를 작성하면 테스트케이스의 수직거리가 짧기 때문에 눈으로 커버해야하는 범위가 훨씬 간결해진다.
    • 만약 하나의 테스트케이스에서 너무 많은 기능을 검증하고 있을때, 테스트가 실패하면 어떤부분 때문에 깨졌는지 확인하는데 시간이 오래 걸리는 부작용을 낳는다.
  • 테스트케이스에서 반복되는 부분도 리팩토링을 하라.
    • 테스트케이스를 짜다보면 반복되는 부분들이 발생한다.
    • 예를 들면 특정 상황을 만들기 위해서 반복해서 Mock객체에 Stub을 통해서 의도한 결과를 만드는 것이 필요한 경우, 부모클래스나 메소드로 분리하면 테스트 작성자는 테스트로 검증하려는 대상에만 집중할 수 있다.
  • 구현체에 의존하지 않도록 작성하라.
    • 테스트는 입력값에 대해 결과값을 확인하는 방식으로 작성한다. 의존하는 객체는 Mock객체를 사용하고, 그 과정에 특정상황을 발생시키기 위해서 의도하는 동작을 하게끔 하는 경우만 Stub을 한다.
    • 구현체가 변경되더라도 테스트 케이스를 변경하는 경우를 최소화 할 수 있다.
    • PowerMock은 구현체에 종속적이기 때문에,  정말 필요한 경우를 제외하고는 최대한 입력값에 대한 결과값을 확인하는 방식으로 테스트케이스를 작성한다.

# TDD Life Cycle

Q. "테스트케이스를 작성하는데 러닝커브가 크지 않나요?"

초반에는 테스트케이스 작성하는 방법에 익숙하지 않기 때문에 기존보다 개발에 시간이 더 오래 걸릴 것이다. 만약에 팀원들이나 리더가 코드 품질이나 테스트 케이스의 중요성에 대해서 인식하지 못하고 있다면 어떻게 해야할까? 사실 그런 상황에서 개인의 노력과 희생으로 익숙해지는 시간이 올때까지 버티는 것은 쉽지않다.

최소한 같은 팀이라면 테스트의 중요성과 코드 품질을 지키기 위한 노력에 대해 충분히 공감하고 있어야 한다. 그래야 나중에라도 생산성이 떨어지는 것 아니냐 등의 볼멘소리가 생기지 않는다. Agile로 일하는 방식을 전파할때도 팀뿐만 아니라 리더들에게도 일하는 방식이나 사고방식의 변화의 중요성을 공유하는 이유가 그것 때문이다.

테스트케이스 작성에 익숙해지면 그 이후부터는 대부분 비슷한 테스트의 반복이 많으며, 테스트케이스 작성때문에 생산성이 떨어지는 상황은 크게 문제가 되지 않는다.

  • 잘 작성된 테스트케이스는 사전과 같다. 나중에 기억이 잘 안나면 찾아보고 작성하면 된다.
    • 단, 기존에 없었던 테스트를 작성해야 하는 상황에는 당연히 스파이킹 하는데 시간을 투자해야한다.
    • 테스트케이스 자체가 문서라고 생각해보라. 물론 문서라는 것이 한번 만들고나면 현행화에 노력이 많이 들지만, 한번 만들어두면 필요할때마다 찾아볼 수 있다.
  • 단위 테스트 작성에 익숙한 사람과 덜 익숙한 사람이 함께 페어프로그래밍(Pair Programming)을 진행해보라.
    • 처음에는 익숙한 사람이 리딩을 하고, 그 이후에는 역할을 바꿔보며 페어로 진행하면 러닝커브를 가장 빠르게 줄일 수 있다.
    • 두 사람의 숙련도 차이가 너무 많이 나는 경우에는 페어를 리딩하는 사람이 지칠 수 있기 때문에, 차라리 별도의 교육으로 진행하는 것이 효율적이다.

이제 시작합시다

지금까지 프로젝트에 단위테스트를 전파하면서 경험을 기반으로 단위 테스트 장점과 테스트 경험이 없는 개발자들이 가지고 있었던 궁금증에 대해 알아봤다. 이번 글을 통해서 단위 테스트를 도입함으로써 개발자들의 일하는 방식이 어떻게 편해질 수 있는지 공감하고,  단위테스트를 시작하는데 동기부여가 되면 좋겠다. 이제 단위테스트를 시작해보자.

원문에서는 하나의 글에서 모두 다뤘지만, 내용이 글 위주로 구성되어 한편에 다루기에 가독성이 떨어지는거 같다는 의견을 들었습니다.  다음글 "Unit Test (단위 테스트) 도입하기 - 2편"에서 단위테스트 작성원칙과 지속하기 위한 방법들에 대해 계속 이어나가겠습니다.


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.