소프트웨어 테스트 종류 정리

소프트웨어 테스트는 코드가 의도한 대로 동작하는지 검증하고, 오류를 조기에 발견하며, 시스템의 안정성과 신뢰성을 확보하기 위한 개발 활동이다.

테스트는 검증 범위에 따라 단위 테스트, 통합 테스트, 시스템 테스트, 인수 테스트로 구분할 수 있다. 목적에 따라 회귀 테스트, 성능 테스트, 부하 테스트, 보안 테스트 등으로도 나뉜다.

테스트 범위에 따른 분류

단위 테스트 (Unit Test)

개별 함수, 클래스, 모듈 검증

통합 테스트 (Integration Test)

모듈과 외부 시스템 사이의 연동 검증

시스템 테스트 (System Test)

전체 시스템의 기능과 비기능 요구사항 검증

인수 테스트 (Acceptance Test)

사용자와 비즈니스 요구사항 충족 여부 검증

단위 테스트 (Unit Test)

단위 테스트는 함수, 메서드, 클래스처럼 작은 코드 단위가 독립적으로 올바르게 동작하는지 검증하는 테스트다.

외부 시스템에 대한 의존성을 최소화하고, 필요한 경우 Mock이나 Stub을 사용해 특정 동작을 모방한다.

예시: 포커 게임의 베팅 금액 검증

function isValidBet(balance: number, bet: number): boolean {
  return bet > 0 && bet <= balance;
}

test("잔액 이하의 양수 베팅은 유효하다", () => {
  expect(isValidBet(1000, 500)).toBe(true);
});

test("잔액을 초과하는 베팅은 무효다", () => {
  expect(isValidBet(1000, 1500)).toBe(false);
});
  • 장점: 실행 속도가 빠르고 오류 원인을 찾기 쉽다.
  • 단점: 데이터베이스 연결이나 실제 네트워크 통신 문제는 검증하지 못한다.
  • 도구: Jest, Vitest, Node.js Test Runner.

통합 테스트 (Integration Test)

통합 테스트는 여러 모듈이나 시스템이 함께 동작할 때 올바르게 연동되는지 검증한다.

개별 함수가 정상이어도 데이터베이스 쿼리, Redis 명령, HTTP 요청, WebSocket 메시지 처리 등에서 오류가 발생할 수 있다. 통합 테스트는 이러한 문제를 발견하는 데 적합하다.

예시: 회원가입 API와 MySQL 연동

test("회원가입 시 사용자가 데이터베이스에 저장된다", async () => {
  const response = await request(app)
    .post("/users")
    .send({
      email: "test@example.com",
      password: "secure-password"
    });

  expect(response.status).toBe(201);

  const user = await prisma.user.findUnique({
    where: { email: "test@example.com" }
  });

  expect(user).not.toBeNull();
});

실제 테스트에서는 테스트용 데이터베이스를 사용하고, 테스트가 끝난 후 생성한 데이터를 정리해야 한다.

  • 장점: 실제 의존성 사이의 연동 문제를 발견한다.
  • 단점: 단위 테스트보다 느리고 환경 설정이 복잡하다.
  • 도구: Jest, Supertest, Testcontainers.

시스템 테스트 (System Test)

시스템 테스트는 애플리케이션 전체를 대상으로 요구사항에 맞게 동작하는지 검증한다.

개별 모듈의 구현보다는 시스템 전체의 동작과 사용자 관점의 결과에 초점을 맞춘다.

예시: 온라인 포커 게임

  • 회원가입 후 로그인할 수 있다.
  • 인증된 사용자가 게임방에 입장할 수 있다.
  • 플레이어들이 베팅하면 게임 상태가 정상적으로 갱신된다.
  • 게임 종료 후 결과와 포인트 정산이 정상적으로 처리된다.

시스템 테스트에는 기능 테스트뿐 아니라 성능, 안정성, 보안 등 비기능 요구사항에 대한 검증도 포함될 수 있다.

인수 테스트 (Acceptance Test)

인수 테스트는 개발된 시스템이 사용자 또는 비즈니스의 요구사항을 충족하는지 확인하는 테스트다.

실제 사용자, 고객, QA 담당자 또는 비즈니스 담당자가 참여할 수 있으며, 반드시 수동으로 진행해야 하는 것은 아니다.

예시: 포커 게임의 정산 요구사항

  • 게임이 정상적으로 종료되면 승자가 결정된다.
  • 승리한 플레이어에게 규칙에 따른 상금이 지급된다.
  • 패배한 플레이어의 베팅 금액이 정확하게 반영된다.
  • 동일한 정산 요청이 반복되어도 중복 지급되지 않는다.

인수 테스트는 구현 세부사항보다 실제 업무 규칙과 기대 결과가 충족되는지 확인하는 데 중점을 둔다.

목적에 따른 테스트 종류

위의 테스트들은 주로 검증 범위를 기준으로 분류한 것이다. 다음 테스트들은 범위와 별개로 특정 목적을 검증한다.

테스트 종류목적예시
회귀 테스트 (Regression Test)기존 기능이 새로운 변경으로 인해 깨지지 않았는지 확인포인트 기능 수정 후 로그인과 정산 재검증
스모크 테스트 (Smoke Test)빌드의 핵심 기능이 기본적으로 동작하는지 빠르게 확인서버 실행, DB 연결, 로그인 확인
탐색적 테스트 (Exploratory Test)사전에 고정된 시나리오에만 의존하지 않고 결함 탐색비정상적인 순서로 게임 조작
성능 테스트 (Performance Test)응답 시간과 처리량 등 성능 특성 확인API 응답 시간 측정
부하 테스트 (Load Test)예상되는 사용자 및 요청 부하에서 동작 확인동시 접속자 증가에 따른 지연 측정
스트레스 테스트 (Stress Test)정상 운영 범위를 넘어 시스템 한계 확인과도한 동시 접속으로 한계 탐색
스파이크 테스트 (Spike Test)부하가 급격하게 증가하거나 감소할 때 안정성 확인이벤트 시작과 동시에 접속 폭증
내구성 테스트 (Soak Test)장시간 운영 시 메모리 누수나 자원 고갈 확인서버를 장시간 실행하며 메모리 관찰
보안 테스트 (Security Test)인증, 권한, 입력 검증 등의 보안 취약점 확인다른 사용자의 계정 정보 접근 시도
복구 테스트 (Recovery Test)장애 이후 정상 상태로 복구할 수 있는지 확인Redis 장애 후 재연결과 데이터 복구 검증
호환성 테스트 (Compatibility Test)다양한 환경에서 정상 동작하는지 확인OS, 브라우저, 클라이언트 버전별 검증
사용성 테스트 (Usability Test)사용자가 기능을 이해하고 편리하게 이용하는지 확인신규 사용자의 게임방 입장 과정 관찰

실시간 게임 서버에서 테스트를 설계하는 방법

Node.js, TypeScript, Colyseus, Redis, MySQL을 사용하는 멀티플레이 게임 서버라면 다음과 같이 테스트를 구성할 수 있다.

단위 테스트

베팅 유효성, 카드 분배, 족보 판정, 팟 계산, 정산 공식

외부 시스템 없이 게임 규칙 자체를 검증한다.

통합 테스트

API + MySQL, 세션 + Redis, 메시지 처리 + DB 저장

실제 의존성을 연결해 데이터와 통신이 올바르게 처리되는지 검증한다.

시스템 및 인수 테스트

로그인 → 매칭 → 게임 진행 → 결과 확정 → 포인트 정산

플레이어의 전체 게임 흐름과 비즈니스 규칙을 검증한다.

부하 및 장애 테스트

동시 접속, WebSocket 재연결, Redis 장애, 서버 종료

운영 환경에서의 처리 한계와 장애 대응 능력을 검증한다.

실무에서 중요한 테스트 전략

모든 테스트를 동일한 비중으로 작성할 필요는 없다. 테스트 비용과 오류 발생 시 피해 규모를 고려해 우선순위를 정하는 것이 효율적이다.

  • 단위 테스트를 많이 작성한다. 빠르게 실행할 수 있으므로 게임 규칙과 계산 로직을 폭넓게 검증한다.
  • 통합 테스트로 핵심 경계를 검증한다. Redis, MySQL, 인증 시스템, WebSocket 통신 등 외부 의존성과의 연동을 확인한다.
  • 핵심 사용자 흐름을 시스템 테스트로 검증한다. 회원가입부터 게임 종료 및 정산까지 실제 시나리오를 테스트한다.
  • 돈과 관련된 로직은 실패 시나리오까지 검증한다. 중복 요청, 동시 정산, 재시도, 서버 중단, 데이터 불일치를 확인한다.
  • 성능 테스트는 실제 병목을 기준으로 진행한다. 단순히 동시 접속자 수만 측정하지 말고 응답 지연, 오류율, CPU, 메모리, 이벤트 루프 지연도 함께 관찰한다.

테스트 피라미드는 이러한 전략을 설명하는 대표적인 모델이다. 일반적으로 빠르고 독립적인 단위 테스트를 넓게 구성하고, 통합 테스트와 전체 시스템 테스트는 검증 가치에 맞춰 배치한다. 다만 모든 프로젝트에 동일한 비율을 적용해야 하는 절대적인 규칙은 아니다.

핵심은 테스트 개수가 아니라 결함을 적절한 단계에서 발견하고, 변경 이후에도 시스템의 정확성과 안정성을 지속적으로 보장하는 것이다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다