테스트란

굴착드릴·2024년 8월 26일

Test란

Test(테스트)는 소프트웨어 개발 과정에서 작성한 코드가 예상대로 동작하는지 확인하고, 소프트웨어의 품질을 보장하기 위해 수행하는 활동을 의미합니다. 테스트는 소프트웨어의 기능적 요구 사항과 비기능적 요구 사항을 검증하여 잠재적인 오류, 결함, 또는 비효율성을 발견하고 해결하는 데 중요한 역할을 합니다.

테스트의 목적

품질 보증(Quality Assurance)

  • 소프트웨어가 정의된 요구 사항을 만족하고, 사용자에게 기대한 대로 동작하는지를 확인합니다. 테스트는 소프트웨어의 신뢰성과 안정성을 높이는 데 도움을 줍니다.

결함 발견 및 예방

  • 개발 초기에 결함을 발견하여 수정하는 것이 비용이 덜 들고 효과적입니다. 테스트를 통해 잠재적인 결함을 미리 발견하여 배포 후 발생할 수 있는 문제를 예방할 수 있습니다.

유지 보수 용이성

  • 테스트는 코드 변경(예: 리팩토링 또는 새로운 기능 추가) 후에도 기존 기능이 잘 작동하는지를 확인하여, 코드의 유지 보수성을 높입니다.

소프트웨어 개선

  • 테스트를 통해 소프트웨어의 성능, 보안, 사용성 등을 평가하고, 이러한 평가를 바탕으로 개선할 수 있습니다.

용어

모킹 (Mokcking)

테스트 중에 실제 객체 대신에 가짜 객체(Mock Object)를 사용하는 것을 의미합니다. 모의 객체는 의존성을 대체하며, 테스트 대상 클래스가 의존성으로 인해 테스트하기 어려운 경우에 주로 사용됩니다.

스터빙 (stubbing)

Stubbing은 모의 객체의 특정 메서드 호출에 대해 미리 정의된 동작이나 값을 반환하도록 설정하는 것을 의미합니다. 스터빙을 통해 테스트 중에 메서드가 호출될 때 어떻게 동작할지 미리 지정할 수 있습니다.

스파이 (Spy)

스파이는 실제 객체의 일부 메서드를 호출하면서도, 특정 메서드의 동작을 제어하거나 관찰하고 싶을 때 사용합니다. 스파이된 객체는 실제 객체를 감싸는 프록시로서, 실제 객체의 메서드를 호출할 수 있는 상태를 유지합니다. 스파이는 기본적으로 실제 객체의 동작을 수행하지만, 필요한 경우 특정 메서드를 모킹하거나 스터빙하여 동작을 변경할 수 있습니다.

스터빙 vs 모킹

특징Mocking (모킹)Stubbing (스터빙)
대상객체메소드
목적실제 객체를 대체하여, 테스트 환경에서 독립적으로 테스트를 수행할 수 있게 함테스트 환경에서 특정 메서드 호출에 대한 동작을 제어하여, 테스트 대상의 행동을 예측 가능하게 만듬
동작모의 객체는 호출된 메서드와 상호작용을 기록하고, 설정된 동작을 수행스터빙된 메서드는 호출될 때 미리 정의된 동작을 수행하거나 값을 반환

모킹 vs 스파이

특징Mocking (모킹)Spying (스파이)
대상가짜 객체(모의 객체)를 사용하여 실제 객체를 대체실제 객체를 감싸는 프록시 객체를 사용
기본 동작모든 메서드 호출에 대해 아무 동작도 하지 않으며 기본값을 반환실제 메서드 호출이 기본 동작
사용 목적의존성을 대체하고 메서드 호출을 기록하거나 특정 반환 값을 지정하기 위해 사용실제 객체의 동작을 일부 유지하면서, 특정 메서드의 동작을 모킹하거나 호출을 검증하기 위해 사용
제어 범위모킹된 객체의 모든 메서드 호출을 제어할 수 있음특정 메서드 호출을 모킹할 수 있지만, 나머지 메서드는 실제 동작을 유지
호출 기록호출된 메서드와 호출 횟수를 기록할 수 있음호출된 메서드와 호출 횟수를 기록할 수 있음 (실제 메서드 호출 포함)
사용 예시단위 테스트에서 의존성을 완전히 대체하여 테스트 격리를 유지하거나, 외부 시스템 호출을 방지하기 위해 사용실제 객체의 상태를 유지하면서, 일부 메서드만 모킹하거나 호출 여부를 검증할 때 사용

Test 종류

Unit Test (단위 테스트)

Integration Test (통합 테스트)
  ├── Module Integration Test (모듈 통합 테스트)
  ├── Slice Test (슬라이스 테스트)
  └── End-to-End (e2e) Test (종단 간 테스트)

System Test (시스템 테스트)
  ├── Functional System Test (기능 시스템 테스트)
  └── Non-Functional System Test (비기능 시스템 테스트)
        ├── Performance Test (성능 테스트)
        │   ├── Load Test (부하 테스트)
        │   └── Stress Test (스트레스 테스트)
        ├── Security Test (보안 테스트)
        └── Usability Test (사용성 테스트)
        
Regression Test (회귀 테스트)
Acceptance Test (인수 테스트)

단위 테스트 (Unit Test)

하나의 모듈이 정상적으로 작동하는 것을 테스트합니다.

이 때 필요한 다른 모듈(의존성)은 mocking하여 테스트를 진행합니다.

private method는 직접적으로 테스트 하지 않으며 public, protected method를 통해 간접적으로 테스트합니다.

단위 테스트의 함정

TDD에서는 단위테스트를 먼저 작성한 후 비지니스 코드를 작성하는 것을 주장합니다.

하지만 스타트업이나 SI처럼 비지니스 요구사항이 계속 변경되는 상황에서 Unit test 작성은 오히려 부작용을 초래할 수 있습니다.

  • 요구사항 변경마다 깨지는 단위 테스트
    • 간단한 변경이지만 수정해야하는 유닛 테스트가 많아 생산성이 떨어질 수 있으며, 이 과정에서 제대로되지 않은 유닛테스트가 작성되어 오히려 소프트웨어 품질을 낮출 수 있습니다.
  • 유닛테스트 작성의 오버헤드
    • 유닛테스트에는 mocking 또는 spy 작업이 반드시 필요하며 이는 많은 코드 작성을 필요로 할 수 있습니다. 제품 출시가 빠르게 되어야 하는 경우 방해요소가 될 수 있습니다.
  • 견고하지 않은 설계
    • 설계 착오가 발생한 경우 unit test는 method 단위를 넘어 class 단위에서까지 재작성해야 합니다.

이러한 경우 수학적인 알고리즘 같은 특정 부분만 단위 테스트로 작성하는 것이 좋을 수 있습니다.

통합 테스트 (Integration test)

두 개 이상의 모듈이 정상적으로 작동하는 것을 테스트합니다.

Slice test

특정 계층만 따로 떼어 test하는 경우입니다.

데이터베이스 계층 검증, web layer 검증이 대표적인 예입니다.

Ex)
데이터베이스 계층: Repository -> Database -> Repository
Web layer: Filter -> Controller -> Controller advice or something -> ...

E2E test

End to end test의 약어입니다.

시스템의 모든 구성 요소가 함께 올바르게 작동하는지, 전체 사용자 시나리오가 기대한 대로 진행되는지 확인하며 이 때 해당 동작에 필요한 모든 구성요소를 결합하여 테스트합니다.

프론트엔드까지의 결합된 것이 진정한 의미의 E2E 테스트이지만 백엔드에서는 api test를 E2E test라고 하기도 합니다.

시스템 테스트

System Test는 시스템의 전체 기능을 요구사항과 비교하여 검증하는 테스트입니다.

비기능적, 기능적 테스트로 나뉠 수 있습니다.

  • Functional System Test (기능 시스템 테스트): 시스템의 기능적 요구 사항을 테스트합니다.
  • Non-Functional System Test (비기능 시스템 테스트): 성능, 보안, 사용성 등 비기능적 요구 사항을 테스트합니다

성능 테스트

부하 테스트

특정 부하 조건 하에서 시스템이 어떻게 동작하는지 평가합니다. 정상적인 동작을 목표로 합니다.

스트레스 테스트

시스템의 최대 한계를 테스트합니다. 실패 이 후 동작에 대해 초점을 둡니다.

부하 테스트 vs 스트레스 테스트

특징스트레스 테스트 (Stress Test)부하 테스트 (Load Test)
목적시스템의 최대 한계를 초과한 상태에서의 성능 평가, 실패 지점 찾기정상 운영 범위 내에서 시스템 성능 평가, 성능 병목 발견
부하 수준시스템의 정상 운영 범위를 초과하는 부하시스템의 예상 최대 정상 부하
결과의 중점시스템이 어떻게 실패하거나 복구하는지를 평가시스템의 응답 시간, 처리량, 자원 사용률 등의 성능 지표 측정

회귀 테스트

회귀 테스트(Regression Test)는 코드 변경 후 기존 기능이 여전히 올바르게 동작하는지를 확인하기 위해 사용하는 테스트 전략입니다. 회귀 테스트는 단위 테스트(Unit Test), 통합 테스트(Integration Test), 시스템 테스트(System Test)를 포함하여 모든 테스트 수준에서 수행될 수 있습니다.

인수 테스트

특정 비즈니스 요구사항 또는 사용자 유즈케이스에 따라 구현되었는지 확인하는 테스트입니다.

비개발자(제품 소유자, QA)에 의해 주로 작성되며 필요에 따라 개발자가 비지니스 요구사항에 따라 작성되며 기능 단위 테스트, rest api와 같은 엔트포인트를 중심으로 검증합니다.

비개발자가 중심이 되어 시나리오를 작성하므로 테스트는 블랙박스테스트 형태를 띄는 것이 좋으며 비지니스 요구사항에 따라 앞서 말했던 모든 테스트가 인수테스트로 제공될 수 있습니다.

E2E test vs 인수 test

인수테스트는 비지니스 관점에서 특정 기능을 검증하는 것이 목표입니다. 흔히 API endpoint test가 주로 인수테스트가 되는 것 뿐이지 인수테스트는 여느 통합테스트, 유닛테스트가 포함 될 수 있습니다.

즉, 비지니스적인 관점에서 내부 서비스의 특정 구간은 확실하게 검증되어야 한다고 생각했을 때 해당 부분에 대한 단위테스트, 통합테스트가 인수테스트로 제공될 수 있으며 보안테스트, 부하테스트 등 역시 포함될 수 있습니다.

고객의 컴플레인으로 결제 로그를 제공 또는 확인해야 하는 절차가 중요하다고 할 때 인수테스트로 로그 수집, 결제 모듈의 단위 테스트와 통합테스트가 인수테스트로 제공될 수 있습니다.

profile
두두두두..

0개의 댓글