ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Effective Unit Testing
    2016. 12. 11. comments
    반응형

    올해 하반기에 팀 동료들과 유지보수의 어려움에 대한 논의가 있었다. 그 중 유닛테스트 추가가 필요하다는 이야기가 나오게 되었다. 우리는 유닛 테스트를 일부 가지고 있었지만 추가 활용의 어려움이 있었다. 유닛 테스트 추가하기 위해서 우리에게 무엇을 필요한지에 대한 논의를 하게 되었다.

    • 유닛 테스트를 추가함으로써 우리는 무엇을 얻게 되는가?
    • 유닛 테스트 추가를 방해하거나 어렵게하는 요인이 있는가?

    우리는 유닛 테스트가 중요하고 코드 안정성 뿐만 아니라 개발 시간을 줄여주는데 도움을 준다는 것에 모두 동의하였다. 하지만 유닛 테스트 작성이 익숙하지 않으며 어떻게 작성하는게 잘 작성된 것인지를 잘 모른다라는 의견이 있었고 특히 네트워크나 DB 인터페이스를 활용하는 시스템 데몬들은 유닛 테스트 작성이 어렵다라는 의견도 있었다.


    원활한 유닛 테스트를 위한 해결 방법 중 1가지로써 책을 선정하여 팀 스터디를 진행하기로 결정하였다. 그렇게 해서 결정된 책이 Effective Unit Testing이다.


    Effective Unit Testing - 8점
    라쎄 코스켈라 지음, 이복연 옮김/한빛미디어


    100% 코드 커버리지 달성이 중요한 게 아니다.


    95%보다는 100%가 물론 듣기 좋다. 다만, 그 차이가 크지 않을 수 있다. 테스트의 가치는 테스트가 확인하지 못한 코드가 어떤 것인가와 테스트가 프로그래밍 실수를 얼머나 정확하게 잡아내는가에 좌우된다. 100% 달성이 단순히 모든 코드를 한 번씩은 실행해보았다는 것만 보장할 뿐일 수 있다. 그러니 커버리지에 대한 강박관념은 버리고 의미 있는 테스트를 작성하는 데 집중하기 바란다.

    • 테스트는 실 사용에 적합한 설계를 끌어내준다.
    • 테스트는 원하는 동작을 명확히 알려주어 군더더기(gold-plating)를 없애준다.

    <Chapter 1 좋은 테스트의 약속>


    NOTE... 버그 수정 비용의 증가


    버그 수정 비용의 증가
    구글이 측정한 바로는 프로그래머가 버그를 만들자마자 즉시 수정한다면 $5를 쓴 것이다. 같은 결함을 프로젝트 전체 빌드 때 발견되면 비용은 $50가 된다. 만약 통합 테스트까지 살아남으면 $500로 증가하며 시스템 테스트에 이르면 $5000까지 치솟는다. 이 수치만 봐도 문제는 가능한 한 빨리 발견해야 한다는 건 이론의 여지가 없다.


    <Chapter1 좋은 테스트의 약속>


    이 책이 좋은 이유는 좋은 테스트가 무엇인지 명확하게 이야기하고 "버그 수정 비용의 증가"와 같이 유닛테스트 장점에 대한 객관적인 데이터를 서술한다는 점이다. 특히 100% 코드 커버리지 달성이 중요하지 않다는 것은 매우 공감한다. 100%를 목표로 하게 되는 순간, 소소하고 크기가 작은 함수들까지 모두 테스트를 만들어야 하게 된다. 경험적으로 100%를 향하게 되면 원하는 동작 검증이 아니라 얼마나 테스트를 많이 만들었는지 집중하게 될 확률이 높아진다고 생각한다. 질보다는 양으로 승부하게 되는 셈이다.


    무엇이 테스트를 좋게 만드는 것일까?

    • 테스트 코드의 가독성과 유지보수성
    • 프로젝트 안에서, 그리고 소스 파일 안에서 코드는 적절히 구조화되어 있는가?
    • 테스트가 무엇을 검사하는가?
    • 테스트는 안정적이고 반복 가능한가?
    • 테스트가 테스트 더블을 잘 활용하는가?

    독립적인 테스트는 혼자서도 잘 실행된다. 격리와 독립성이 중요한 이유는 그것이 없다면 테스트를 실행하고 관리하기가 훨씬 어렵기 때문이다. 단위 테스트를 실행하기 위해 개발자가 해야할 귀찮은 작업이 훨씬 많아진다.


    <Chapter 2 좋은 테스트란?>


    독립적인 테스트(격리와 독립성) 이야기는 꽤 반가운 이야기였다. 나는 테스트는 반드시 독립적이어야 한다고 생각한다. 독립적인 테스트를 만들지 않으면 이미 만들어놓은 테스트가 어느 순간 동작하지 않을 가능성이 높아진다. 이미 작성된 대부분의 테스트를 재작성하거나 구축하는 것은 낭비이기 때문이다. 독립적인 테스트의 중요성에 대해서 상관없거나 무관심한 사람과 함께 일한다면 중복이나 낭비에 대한 개념이 없는 사람이니 되도록이면 멀어지는게 좋다.


    독립적 테스트와 관련된 경험한 사례를 이야기하면,

    1. 유닛테스트를 다른 레파지토리에 운영하고 버전으로 운영하자.
    2. 모든 팀이 활용하는 계측기로 자동화 테스트를 돌리자. 환경이 무너질 가능성이 있지만 구축하면 결국 도움이 될 것이다.


    1번은 당췌 어떤 장점을 얻게 되는지 몰라서 강력하게 거절했다. 유닛 테스트를 실행할 때 마다, 버전을 고려해야 하는 불편함이 오히려 생기게 되는데 말이다. 2번 사례도 환경이 매번 무너지면 결국 도움이 안될 것이라고 주장했지만 결국 시간을 들여서 구축을 하였다. 아쉽게도 구축한 테스트 환경의 운영은 한달도 안되서 무너졌고 1-2번 재정비했지만 결국 그 이상은 운영하지 않았다.


    테스트 주도 개발 책에서도 독립적인 테스트 관련하여 일부 답을 얻을 수 있다.

    TDD의 부산물로 자연히 생기는 테스트들은 시스템 수명이 다할 때까지 함께 유지돼야 할 만큼 확실히 유용하다. 하지만 이 테스트들이 다음과 같은 다른 종류의 테스트들을 대체할 수 있을 거라고 예상해서는 안된다.

    • 성능테스트
    • 스트레스 테스트
    • 사용성 테스트
    <17장>


    Effective Unit Testing 책 내용 대부분은  "Part 2 테스트 냄새"에 해당한다. 여기에서는 다양한 예시와 나열하고 저자의 해결책들을 확인해볼 수 있다. 아래는 책 내용 중  조건부 테스트라는 내용을 요약한 것이다.


    유지보수성의 조건부 로직과 비슷하다. 여기에서는 아예 조건문 때문에 테스트가 동작안하는 상황을 의미한다. Assert가 조건문을 통해서 실행되는지 확인하라. 어쩔수 없이 if문 조건이 필요하다면 if문 조건까지도 assert로 검증하라.


    예를 들어 아래와 같은 assert에 대해서,
    if( process.exitCode() == 0)
    {
         assertEquals(“hello.txt”, process.output);
    }


    다음과 같이 변경하자.
    assertEquals(0, process.exitCode())
    assertEquals(“hello.txt”, process.output);


    <Chapter 6 신뢰성>

    참고로 예제 코드 대부분이 자바로 작성되었기 때문에 최소한 객체지향언어에 대한 이해가 필요하다.


    이 책은 다른 Effective 시리즈와 같이 해당 기술에 경험이 없는 사람이라면 단순히 읽기에는 적절치 않다고 생각한다. Chapter1만 읽고나서 다양한 유닛테스트를 먼저 작성해보는 것을 추천하고 싶다. 그리고 나서 Chapter2를 읽어보게 되면 이미 내가 작성한 유닛 테스트를 가지고 고쳐나가는 실습을 할 수 있으며 집중력도 높아질 것이다.


    반응형

    댓글

Designed by Tistory.