본문 바로가기
대학공부/소프트웨어공학

Software Testing

by 진진리 2023. 10. 6.
728x90

Test를 pass하는 기준은 expected output: 테스팅을 통해 알 수 있는 것은 expected output과 actual output이 같다는 것

  • 테스팅이 어려운 이유  
    • 실제 사용되는 환경에서 검증하기 어려움
    • 소프트웨어가 처리해야 하는 모든 입력값의 범위 및 조합에 대한 테스팅이 현실적으로 불가능
    • 오작동이 입력값외에 환경에 영향을 받을 수 있음
    • multithread 프로그램인 경우 소프트웨어의 행위 및 출력이 수행할 때마다 달라짐
    • 프로그래밍 언어에 따라 다른 테스팅 기법 적용
    • 결함이 없다고 보장 불가능
  • Combinatorial testing: 시스템에 대한 입력 매개변수에 대해 모든 가능한 개별 조합을 테스트
  • Random testing: random possible input을 생성, 모든 input의 가치가 동등하다고 가정
  • Systematic testing: 특히 가치있는 input을 선택하기 위해 노력. 보통 자주 fail하거나 전혀 fail하지 않은 class의 대표자를 선택

 

  • Error: 사람에 의한 실수
  • Fault: 소프트웨어에 나타난 error의 결과
  • Failure: 기대 결과를 생성하지 못하는경우
    • Fault of Omission: specify되었지만 program되지 않은 behavior
    • Fault of Commission: program되었지만 specify되지 않은 bahavior

Program Analysis Tools

  • Static Analysis Tools(정적 분석 도구)
    • 실행없이 프로그램의 properties 평가, 소스코드를 분석하여 코딩 표준이 준수되었는지 여부 분석 가능
    • 모든 실행 경로에 대한 심층 분석. 정해진 규칙과 기준에 따른 분석
    • 문제를 표시함으로써 에러를 빠르게 수정. 프로그램의 전체 구조 파악 쉬움
    • 발견할 수 있는 오류: Un-initialized vairables, mismatch between actual and formal parameters, variables decleared but never used.
    • 한계: false 알람이 많음(오류가 아님에도 잠재적인 오류라고 표시하는 경우가 많음)
  •  Dynamic Analysis Tools(동적 분석 도구)
    • 프로그램이 실행되고 행동이 기록됨
    • Capture-and-replay tools: 사용자와 시스템 간, 스레드 간의 상호 작용을 기록하여 이를 통해 오류를 찾음.
    • 한계: 코드 내의 해당 기능을 위한 probing statement가 오버헤드가 됨 → “probing effect”: probing statement가 있을 때와 없을 때 프로그램의 behavior가 달라질 수 있음

  • Program Slicing: 오류에 영향을 미치는 프로그램 부분(statement)을 찾음.
    • 프로그램이 크고 복잡할 때 특정 ouput 오류가 발생한 경우 원인을 찾기 위해 디버깅하는 경우 사용
    • 프로그램의 행동을 이해하는데 도움
    • procedure/function calls, parameters가 있는 경우 하기 어려움
  • Control Flow Graph
    • nodes = 소스코드의 regions (basic blocks): single entry와 single exit point를 가진 최대 region
    • directed edges = 한 region 끝에서 다른 region의 시작으로 진행 가능


Software Testing 종류

  • Functional testing (=Black-box testing)
    • 시스템의 내부 구조를 고려하지 않고 기능 명세를 기반으로 테스트케이스 생성
    • input space를 partition 하고, 각 카테고리와 카테고리 간의 boundaries를 test
    • 명세서의 logic이 구현되지 않은 경우 missing logic 발견 가능
    • 설계하고 실행하기에 비교적 저렴
    • program code 불필요, 명세의 설명과 testability를 평가하기에 유용
  •  Structural testing (=white-box, glass-box, code-based)
    • 테스트케이스에서 빠진 부분을 알 수 있는 방법 : 만약 어떤 테스트케이스에 의해서도 실행되지 않는 프로그램의 부분(CFG의 node 혹은 edge)이 있다면 그곳에서의 fault가 발견되지 못함
    • 실행되지 않은 요소의 해석: 명세와 실행 간의 자연스런 차이, 또는 소프트웨어 혹은 개발 과정의 결점(실행에서 포함되지 않은 부적절한 명세, 명세와 다른 coding practice, 부적절한 기능 테스트케이스)
    • 지표가 되는 Coverage
      1. Statement coverage: 각 statement (CFG에서의 node)가 적어도 한 번은 실행되어야 함
      2. Branch(=Decision) coverage: 각 branch가 적어도 한 번은 실행되어야 함
      3. Condition coverage: 조건문 내의 개별 조건들이 적어도 한 번은 각각 T, F가 되어야 함
      4. MC/DC: 독립적으로 결과에 영향을 미치는 모든 조건이 나타나야 함. safety-critical software일 때 사용
      5. Multiple condition coverage: 모든 조건의 조합이 적어도 한 번은 실행되어야 함
      6. Path coverage: 모든 경로가 적어도 한 번은 실행되어야 함
  • Model-based testing
    • 요구사항/코드로부터 자동 생성된 모델(주로 finite state machine)에 coverage 개념을 적용
    • State coverage, Transition coverage: 테스트케이스가 모든 state와 transition을 적어도 한 번은 수행해야 함
    • FSM model과 실제 구현된 프로그램이 같은지, required properties를 만족하는지 확인해야 함
    • 모델의 종류
      • FSM: 선택한 입력에 따른 결과를 평가하는데 좋음. 입력의 다양한 조합에 의해 특정 상태를 초래. 모델이deterministic한 경우 작동.
      • Statechart: 복잡한 실시간 시스템의 다양한 동작을 설명하는데 좋음.
      • UML: 시스템의 복잡한 동작을 설명할 수 있는 시각적 모델을 만드는 법이 포함.
  • Fault-based(=Mutation) Testing
    • artificial bugs를 심은 후 테스트케이스로 검증. 오류가 발견되면 “mutant is killed”라고 표현
    • 테스트케이스가 실제 오류를 찾아내는데 있어서 얼마나 효과적인지 등 테스트케이스의 quality를 판단 가능
    • 언어에 따라 잘 발견되는 버그의 종류를 바탕으로 mutation rule 생성
    • Mutation testing tool: Stryker

Testcase

  • Concolic Testing: concrete + symbolic의 hybrid software verification 기법
    • 자동 테스트케이스 생성 방법(automated theorem prover)으로 코드의 가능한 모든 path를 가는 testcase를 만드는 방법(path coverage 만족), if문에 포함된 식의 해를 자동적으로 구한 후 다시 적용하는 것을 반복.
    • concolic testing tools: CREST, KLEE
  • Metamorphic Testing
    • expected output을 명세하기 어려워 테스트케이스를 만들기 어려울 때 사용
    • 테스트케이스를 '재사용'
    • Search engine, Compiler, Simulator, ML-based system에서 자주 사용됨
    • Metamorphic Relation
      • merge(L1,L2) = Merge(L2, L1), merge(L1, L1) = L1 
      • 어떻게 metamorphic relation을 정의하냐에 따라 valid testcase를 결정