개발/학교 수업

[소개원실] Testing

Woogie2 2021. 9. 28. 19:51
반응형

1. Testing

Traditional Quality Assurance

전통적인 QA 방법은 9단계로 진행된다.

  1. 머리 속에서 코드 실행해보기
  2. IDE warning으로 인지해서 고치기
  3. complier warnings 고치기
  4. 코드 리뷰(피어 리뷰)
  5. Unit testing (black +white)
  6. Integration testing
  7. System testing
  8. Alpha testing
  9. Beta testing

얼마나 테스트를 진행해야할까?

  • Bad: "Until time to ship"
  • better: Lines of Test / Lines of code
    • 1.2~1.5 값은 터무니 없는 값이 아니다. 적정하거나 더 많이 수행된다.
    • 실제 프로덕트 시스템에서는 더욱 많은 테스트가 진행
  • more better Question: "나의 테스트가 얼마나 철저한가?"
    • Formal methods
    • Coverage mesearment !!
    • 이 수업에서는 후자인 커버리지 측정에 집중하고, 전자는 steady transaction을 통해 얻고자 함.

Metrics

  • X가 적어도 하나의 테스트에 의해서 한 번 이상 실행되는 경우 X가 커버되었다고 한다.
  • Coverage(인기있는 메트릭임) = % coverd of total available
  • Quality vs Cost의 트레이드 오프
  • Coverage의 종류들
    • X = methods -> method/function coverage
    • X = statements -> statement/line/basic-block coverage
    • X = branches -> branch coverage
    • X = paths -> path coverage

Measuring Coverage - Basics

  • S0: every method callsd
  • S1: every method from every from every call site
  • C0: every statement
  • C1+decision coverage: every subpression in conditional(조건문)
  • C2: every path (어려움, 실질적으로 가치가 있는지 반대 의견이 있음)

Identifying What's Wrong in Your Code

  • 코드가 깨끗하지 못하다고 판단하는 기준을 어떻게 잡을까?
  • 어떻게 깨끗하지 못한 코드를 개선할 수 있을까?
    • 양적 분석: software metriscs
    • 질적 분석: code smell
      • 일반적인 코드 스멜(각 항목에 대한 설명은 제가 이해한 바를 토대로 작성하였습니다. 오개념이 있을 수 있으니 틀린 점은 댓글로 알려주세요.)
        • 응용 프로그램 수준
          • 이해하기 어려운 이름(함수, 모듈, 클래스, 변수 등): 이러한 것들이 문서로 커뮤니케이션이 안된 상태면 더욱 문제.
          • 중복 코드: 비슷한 코드들이 여기저기에 존재
          • 억지스러운 복잡성: 더욱 간단히 디자인 패턴을 바꿀 수 있지만, 귀찮아서 복잡성을 계속 가져가는 경우(라고 이해함)
          • Shotgun surgery: 하나의 기능을 복붙해서 여러 클래스나 함수에 사용하는 경우 발생
          • 사이드 이펙트 제어 불가: 유닛테스트로 잡아낼 수 없는 런타임 에러
          • Variable mutations: 런타임에서 변수가 변하는 것을 통제, 디버깅 하는 것이 어렵다. 따라서 const와 같이 immutable한 것들을 주로 쓰자.
          • Boolean blindness: 실제 if-else문과 같은 곳에서 boolean의 의미를 파악하는 것은 해당 path를 다시 읽게 만들고, 여러번 boolean을 생각하다 보면, 머릿속에서 꼬이는 것을 말하는 듯 하다. ("easy to assert on the opposite value and still type checks"라고 원문에 적혀있으나 아직은 무슨 뜻인지 정확히 이해하진 못했다.)
            • 예시코드
            • if 1 != 1: return True else: return False
        • 클래스 수준
          • 너무 큰 클래스
            • 기능에 대한 욕심: 다른 클래스의 메서드를 과도하게 사용하는 경우
            • 부적절한 관계: 다른 클래스에 대해 종속성을 갖게 되는 경우
          • Refused bequest: 자식 클래스가 부모의 클래스를 상속받아 override하는 경우, 충실히 구현하지 못하는 때 발생한다. 이는 LSP(Liskov Substitution Principle)를 위반하게 되는데 해결하려면 상속 관계를 없애고 delegation(위임)하기.
          • 게으른 클래스/freeloader: 클래스가 하는 일이 너무 적음.
          • 리터럴의 과도한 사용: 상수를 가독성 좋게 만드는 리터럴을 너무 자주 많이 사용하는 경우, 다른 Resource(파일 or 서버 등등)로 분리하여 관리할 수 있을 것임.
          • Cyclomatic complexity: 너무 많은 branch와 loop -> 코드를 더욱 작게 쪼갤 수 있음을 말한다. 더욱 작은 단위로 분리하자.
          • DownCasting: 부모 클래스 객체를 자식 클래스 객체로 type 캐스팅 하는 것을 말함. downcast는 추상 모델을 깨버릴 위험이 있다. 따라서 타입캐스트 사용시 abstaction을 수정하거나 삭제하기.
          • Orphan variable OR constant class: 상수만을 가진 클래스는 클래스보다는 변수로 구현하는게 나을 것 같음. 아니면 리터럴로. Orphan variable는 더이상 참조가 존재하지 않는 변수로, 자바에서는 자동적으로 가비지 컬렉션이 되지만, 다른 언어에서는 메모리 누수가 일어날 수 있다.
          • Data clump: 여러 변수들이 프로그램의 여러 파트에서 들어올 경우 발생. 이 변수 그룹은 의존성을 가지게 되며, 리팩토링이 필요하다. 분리된 변수 객체를 하나의 객체로 합쳐서 받는 것이 해결책이라고 하는데, 함수형 컴포넌트를 주로 사용하는 리액트에서와 뭔가 개념적으로 충돌하는 것 같다. 추가적으로 고민해보기.
        • 메서드 수준
          • too many parameters
          • Long method
          • Excessively long identifiers: 링크 참조
          • Excessively short identifiers
          • Excessive return of data
          • Excessive comments
          • Excessively long line of code
        • 안티패턴

Quantative: Metrics

  • 목표수치
    • code-to-test ratio: 1:2 이하
    • C0(statement) coverage: 90% 이상
    • Assignment-Branch-Condition score(ABC score): 메서드 당 20 미만
    • Cyclomatic complexity: 메서드당 10 미만(NIST)
  • “Hotspots”: 여러 메트릭들이 기준치를 만족하지 못하면 경고해주는 코드 라인.
  • 메트릭을 그냥 무시하지 말고, 왜 그런 수치가 나오는지 고민할 것!
  • 리팩토링이 필요한 부분을 더욱 잘 선택할 수 있다.

Cyclomatic complexity

  • 정의: 코드 상에서 선형적으로 독립적인 경로들의 개수
  • E– N+2P (edges, nodes, connected components)
  • 각 경로는 다른 경로에 포함되지 않는 edge를 적어도 하나 이상 가지고 있어야 한다.
  • ex)
  • 위 사진을 예시로 계산하는 경우, E=9, N=8, P=1이다 따라서 Cyclomatic Complexity=3

테스트 종류 중 무엇을 선택할 것인가?

  • Unit: run fast, high coverage, Fine resolution, Many mocks, 인터페이스는 테스트 하지 않음.
  • Function or module
  • Integration/System: run slow, Low coverage, Coarse resolution, Few mocks, test interfaces
  • 어느 하나를 맹신하지 말자. 두루 활용할 것. 한 계층의 테스트가 못 잡는걸 다른 계층의 테스트는 잡아낼 수 있음. 상호 보완적임

이외의 테스트들

  • Acceptance testin
  • Smoke/sanity testing: 심각한 오류가 발생하는지 간단히 테스트함
  • Compatibility testing: 호환성을 테스트 (ex: 웹 구현 후 브라우저마다 테스트하기)
  • Fault injection: bad inputs, bad returns에 잘 대응 되었는지 확인.
  • Performance testing: Load/stress/scalability testing
  • Usability testing(사용성)
반응형