ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 단위 테스트 1장
    책/단위 테스트 2022. 6. 26. 23:29

    1. 단위테스트란?

    • 테스트에 드는 노력을 가능한 줄이고 그에 따르는 이득은 최대가 되어야 한다.
      • 즉, 무난하게 성장하고 유지보수가 많이 필요하지 않고 끊임없이 변화하는 고객의 요구에 신속히 대응할 수 있는 프로젝트이다.
    • 이 책을 통해 어떤 단위테스트 기술이 좋은지를 구별하고 공통적인 안티패턴을 피하는 방법을 배운다.

    1.1 단위 테스트 현황

    • 테스트를 작성하는게 현재 소프트웨어 시장에서 당연한 현상이다.
    • 하지만 일부 테스트는 오히려 예외를 잘 확인하지 못할 뿐더러 유지보수하는데 오래걸리는 효과만 얻는다.
    • 이 책을 통해 좋은 테스트를 구성하는 법을 배우게 된다.

    1.2 단위 테스트 목표

    • 단위 테스트 활동이 더 나은 설계로 이어진다.
      • 비즈니스 코드에 단위 테스트를 작성하면 일반적으로 더 나은 설계로 이어지기 때문이다.
    • 하지만 이는 부수효과로 소프트웨어 프로젝트의 지속 가능한 성장을 가능하게 하는 것 이 주된 목표이다.
    • 개발 초기단계에선 테스트가 없으면 테스트가 있는거보다 오히려 프로젝트 개발 속도가 더 빠르다.
    • 하지만 개발이 진행되가면서 이전과 같은 속도를 갖기는 매우 힘들다.
    • 하나의 코드를 바꾸면 그 코드를 쓰고 있는 다른 코드가 예기치 않은 오류가 발생할 수 있다.
    • 테스트를 포함해서 코드를 짜는 경우는 개발 초기에 비해 그렇게 많은 시간이 걸리지 않는다.
      • 이렇게 테스트를 구성하지 않아 개발 속도가 빠르게 감소하는 현상을 소프트웨어 엔트로피 라고 한다.
    • 지속적인 리팩터링과 정리를 하지 않고 방치하면 시스템이 점점 더 복잡하고 무질서 해진다.
    • 테스트는 안정망 역할을 하며 대부분의 버그에 보험을 제공하는 도구의 역할을 한다.
    • 하지만 테스트는 초반에 노력이 많이 필요하다. 하지만 지속적인 유지보수를 생각한다면 테스트를 짜는 노력은 짜지 않을 때보다 훨씬 적다.
    • 즉, 테스트를 구성함으로써 지속성과 확장성, 장기적으로는 개발 속도를 유지할 수 있다.

    1.2.1 좋은 테스트와 좋지 않은 테스트를 가르는 요인

    • 위처럼 테스트의 장점에 대해 얘기했지만 나쁜 테스트를 짠다면 이와 같은 이점을 얻을 수 없다
    • 아예 테스트를 짜지 않는 것에 비해 향후 개발 속도를 비교하자면 더 적은 시간이 걸리겠지만 그럼에도 많은 시간이 걸린다.
    • 테스트를 구성할 땐 그 가치와 유지 비용을 모두 고려한다.
    • 아무 가치없는 테스트보다 고품질의 테스트만이 테스트 집합에 남을만한 유형이다.
    • 테스트가 많으면 많을 수록 좋다고 생각하는 사람이 있지만 이는 그렇지 않다.
    • 필요하지 않은 테스트나 겹치는 테스트의 경우 향후 기능을 변경할 때 유지보수를 다시 해야한다.

    1.3 테스트 스위트 품질 측정을 위한 커버리지 지표

    • 프로그래머가 특정 커버리지 지표를 목표로 하는 것은 좋지않다.
    • 테스트 스위트(모음) 품질을 결정하는데 지표를 의존하면 안된다.
      • 커버리지 지표
      • 테스트 모음이 소스코드를 얼마나 실행하는지를 백분율로 나타낸다.
    • 커버리지 지표는 일반적으로 높을 수록 좋다. 하지만 높다고 양질의 테스트 모음이라고 보장할 수는 없다.

    1.3.1 코드 커버리지 지표에 대한 이해

    • 많이 사용되는 커버리지 지표로는 코드 커버리지(테스트 레버리지)분기 커버리지 가 있다.
    • 코드 커버리지를 계산하는 식은 실행 코드 라인 수/ 전체 라인 수 입니다.
    public static boolean isLongString(String input) {
      if (input.length > 5)
        return true;
      return false;
    }
    ​
    public void test() {
      boolean result = isLongString("abc");
      Assertions.isEqual(false, result);
    }

    이와 같은 메소드가 있고 이때 "abc" 를 input 으로 넣으면 메서드 전체라인 수는 5 줄이고 테스트가 실행되는 라인수는 4이므로 4/5 = 80% 이다.

    똑같은 역할을 하는 코드를 다음과 같이 바꿔보자

    public static boolean isLongString(String input) {
      return input.Length > 5;
    }
    ​
    public void test() {
      boolean result = isLongString("abc");
      Assertions.isEqual(false, result);
    }

    코드의 역할을 바꾸지 않았지만 테스트 커버리지는 100 % 가 되었다.

    1.3.2 분기 커버리지 지표에 대한 이해

    분기 커버리지는 코드 라인 수를 사용하는 대신 if 문과 switch 문과 같은 제어 구조에 중점을 둔다.분기 커버리지를 계산하는 식은 통과 분기/전체 분기 수 입니다.

    public static boolean isLongString(String input) {
      return input.length > 5;
    }
    ​
    public void test() {
      boolean result = isLongString("abc");
      Assertions.isEqual(false, result);
    }

    isLongString 메소드에서 발생하는 분기는 총 2개입니다. 여기서는 1개의 분기에 대해서만 테스트 하므로 1/2 = 50 % 입니다.

    1.3.3 커버리지 지표에 관한 문제점

    테스트 대상 시스템의 모든 가능한 결과를 검증한다고 보장할 수 없다.외부 라이브러리의 코드 경로를 고려할 수 있는 커버리지 지표는 없다.

    public static boolean isLongString(String input) {
      boolean wasLastStringLong;
      boolean result = input.length > 5;
      wasLastStringLong = result ; // <--- 첫번째 결과
      return result; // <--- 두번째 결과
    }
    ​
    public void test(){
      boolean result = isStringLong("abc");
      Assertions.isEqual(false, result) // <-- 두번째 결과만 입증
    }

    커버리지 지표는 기반 코드를 모두 테스트 했다고 보장할 수 없으며 일부만 실행된 것을 보장한다.

    public void test(){
      boolean result1 = isLongString("abc") // true
      boolean result2 = isLongString("abcdef") // false
    }

    위 테스트 코드는 모든 분기를 테스트 하므로 테스트 커버리지는 100 %지만 아무것도 검증(Assertions) 을 하고 있지 않기 때문에 전혀 쓸모있지 않다.

    public static int parse(String input) {
      return Integer.parseInt(input);
    }
    ​
    public void test() {
      int result = parse("5");
      Assertions.isEqual(5, result);
    }

    분기, 코드 커버리지 지표는 100 %이다. 하지만 모든 경우의 수를 넣지 않았다.

    • null빈 문자열
    • 3.14(정수가 아님)
    • 12345..... (너무 긴 문자열)

    이와 같이 수많은 edge case 가 있지만 테스트에서는 모든 케이스를 다루는지 확인할 방법이 없다.

    1.3.4 특정 커버리지 숫자를 목표로 하기

    • 테스트 커버리지 지표는 그 자체 즉, 얼마나 커버 했는지로 봐야지 목표로 여겨서는 안된다.
    • 테스트 커버리지가 낮다면 문제지만 높다고 해서 큰 의미는 없다.

    1.4 무엇이 성공적인 테스트 스위트를 만드는가?

    • 성공적인 테스트 스위트는 다음과 같은 특성을 갖고 있습니다.
      • 개발 주기에 통합돼 있습니다.
      • 코드베이스에서 가장 중요한 부분만을 대상으로 합니다.
      • 최소한의 유지비로 최대의 가치를 끌어냅니다.

    1.4.1 개발 주기에 통합돼 있음

    • 코드가 변경될 때마다 아무리 작은 것이라도 실행 돼야 합니다.

    1.4.2 코드베이스에서 가장 중요한 부분만을 대상으로 함

    • 시스템의 가장 중요한 부분에 단위테스트 노력을 기울이고, 다른 부분은 간략하게 또는 간접적으로 검증하는 것이 좋다.
    • 비즈니스 로직 테스트가 시간 투자 대비 최고의 수익을 낼 수 있다.

    1.4.3 최소 유지비로 최대 가치를 끌어냄

    • 결론적으로 테스트의 가치가 이를 유지하는 비용보다 높아야 테스트를 작성하는 이유이다.

    ' > 단위 테스트' 카테고리의 다른 글

    Classicist TDD vs Mockist TDD  (0) 2022.07.25
    3. 단위 테스트 구조  (0) 2022.07.13

    댓글