1. 테스트 방식의 분류
화이트박스 테스트 vs. 블랙박스 테스트
- 화이트박스 테스트: 코드 내부 구조를 이해하고 테스트를 설계합니다.
- 소프트웨어의 내부 구조, 코드, 알고리즘, 로직을 이해한 상태에서 테스트를 수행합니다.
- 내부를 들여다보고 테스트한다고 해서 화이트박스라고 불립니다.
- 예: 유닛 테스트, 코드 커버리지 테스트.
- 블랙박스 테스트: 내부 구현을 모른 채, 기능과 요구사항 중심으로 테스트합니다.
- 소프트웨어의 내부 구조나 동작 방식은 고려하지 않고, 입력값과 출력값만을 테스트합니다.
- 상자를 열어보지 않고 테스트한다고 해서 블랙박스라고 불립니다.
- 예: 시스템 테스트, 기능 테스트, UI 테스트.
자동화 테스트 | 수동 테스트 | |
목적 | 코드를 기반으로 오류를 찾아내고, 모든 코드 경로와 로직이 올바르게 작동하는지 논리적 오류를 검출합니다. | 사용자의 요구사항에 따라 소프트웨어가 올바르게 작동하는지 확인합니다. 기능, UI, 요구사항 충족 여부 등 외부 동작에 초점을 맞춥니다. |
특징 | 코드 커버리지 확인합니다. 코드의 모든 실행 경로를 테스트합니다. | 입력값과 출력값의 조합을 테스트합니다. 오류 처리, 유효성 검사, 사용자 시나리오 확인합니다. |
장점 | 코드의 논리적 결함을 발견합니다. 성능 최적화 및 코드 품질 개선 가능합니다. | 사용자 관점에서 문제를 발견하기 쉽습니다. 내부 구현과 무관하게 기능적 요구사항을 검증합니다. |
단점 | 내부 구현에 의존하여 사용자 관점의 오류를 발견하기 어려웁니다. 복잡한 시스템의 경우 모든 경로를 테스트하기 어렵고 비용이 높습니다. | 코드 내부의 논리적 오류나 성능 문제를 발견하기 어렸습니다. 테스트 범위를 정의하는 것이 어려울 수 있습니다. |
2. 테스트 유형
단위 테스트 (Unit Test)
- 단위 테스트는 소프트웨어의 가장 작은 독립적 단위(보통 함수, 메서드, 클래스 등)를 테스트하는 과정입니다.
- 각 단위를 개별적으로 실행하여, 입력에 대한 출력이 예상대로 나오는지 확인합니다.
- 독립적이며 외부 의존성을 모의(Mock) 객체로 테스트 합니다.
- 주요 목적
- 결함 조기 발견: 코드를 작성하는 단계에서 오류를 발견하고 수정할 수 있습니다.
- 코드 안정성 보장: 변경 사항이 기존 기능에 부정적인 영향을 주지 않도록 방지합니다.
- 리팩토링 지원: 테스트가 작성되어 있다면 리팩토링 과정에서 기능이 깨지지 않는지 확인할 수 있습니다.
- 문서화 역할: 테스트 코드는 코드의 예상 동작을 보여주는 실질적인 예제 역할을 합니다.
- 장점: 빠른 피드백 제공, 코드 품질 향상.
- 코드 단위의 정확성 보장: 각 모듈(함수/메서드)이 올바르게 동작하는지 검증합니다.
- 빠른 피드백 제공: 단위 테스트가 실패하면 바로 문제를 파악하고 수정 가능합니다.
- 회귀 방지: 기존 코드가 변경될 때 발생할 수 있는 오류를 방지합니다.
- 테스트 작성 주의사항
- 독립성 보장: 테스트는 독립적으로 실행되어야 하며, 다른 테스트에 의존하지 않아야 합니다.
- 단일 동작 테스트: 각 테스트는 하나의 동작이나 결과만 검증해야 합니다.
- 명확한 이름 사용: 테스트 이름은 테스트의 의도를 명확히 나타내야 합니다.
- 경계 조건 테스트: 정상 케이스뿐만 아니라, 경계 값에 대한 테스트도 포함합니다.
- Mock 사용: 외부 의존성을 격리하기 위해 Mock 객체를 사용합니다.
- 도구 예: JUnit(Java), Pytest(Python).
Java 예제 (JUnit):
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalculatorTest {
@Test
public void testAddition() {
// Arrange
Calculator calculator = new Calculator();
int a = 5;
int b = 3;
// Act
int result = calculator.add(a, b);
// Assert
assertEquals(8, result, "Addition should return the correct sum");
}
}
단위테스트 한계
- 단위 테스트는 개별 모듈만 확인하므로, 시스템 수준에서의 문제는 발견할 수 없습니다.
- 외부 시스템(DB, API)과의 통합 문제를 검출하기 어렵습니다.
- 잘못된 테스트 코드는 오히려 혼란을 초래할 수 있습니다.
b) 통합 테스트 (Integration Test)
- 통합 테스트는 여러 개의 모듈이나 컴포넌트가 상호작용할 때 올바르게 동작하는지 확인하는 테스트 단계입니다
- 단위 테스트가 통과한 이후에 수행하며, 모듈들이 결합될 때 발생할 수 있는 문제를 확인하는 데 초점을 맞춥니다.
- 외부 API, 데이터베이스, 파일 시스템 등과의 상호작용 테스트 포함합니다.
- 장점: 모듈 간 호환성 확인, 예기치 못한 오류 발견.
- 상호작용 중심: 모듈 간의 데이터 교환, 호출, 상태 변화 등을 테스트합니다.
- 통합 결함 발견 : 서로 다른 모듈이나 서브시스템 간의 데이터 흐름과 통신이 올바르게 이루어지는지 확인합니다.
- 시스템 안정성 보장: 다양한 모듈이 실제 환경과 비슷한 상황에서 함께 작동할 때의 안정성을 검증합니다.
- 종속성 관리: 데이터베이스, 외부 API, 파일 시스템 등 외부 의존성과의 상호작용을 테스트합니다.
- 테스트 작성 주의사항
- 실제 환경 모방: 테스트 환경을 실제 환경과 최대한 비슷하게 구성합니다.
- 독립적 실행 가능: 각 테스트는 독립적으로 실행 가능하도록 설계해야 합니다.
- Mock과 실제 의존성 사용의 균형:
Mock을 사용해 불필요한 복잡성을 줄이는 동시에, 실제 의존성을 테스트할 부분도 포함해야 합니다. - 에러 로그 확인: 통합 테스트 실패 시 명확한 로그를 남겨 디버깅을 쉽게 합니다.
- 도구 예: Spring Boot 통합 테스트(Java).
Java 예제:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testGetUserDetails() {
// Act
ResponseEntity<User> response = restTemplate.getForEntity("/api/users/1", User.class);
// Assert
assertThat(response.getStatusCode().is2xxSuccessful()).isTrue();
assertThat(response.getBody().getName()).isEqualTo("John Doe");
}
}
통합테스트 한계
- 시간 소요: 테스트 범위가 크기 때문에 실행 시간이 오래 걸릴 수 있습니다.
- 복잡성 증가: 여러 모듈과 시스템 간의 상호작용을 테스트하기 때문에 복잡도가 높아질 수 있습니다.
- 결함 원인 식별 어려움: 오류가 발생하면, 단위 테스트에 비해 문제의 원인을 찾기 어려울 수 있습니다.
성능 테스트 (Performance Test)
- 성능 테스트는 소프트웨어 시스템이 특정 조건에서 얼마나 효율적으로 동작하는지 확인하기 위해 수행되는 테스트입니다.
- 이는 시스템의 속도, 안정성, 확장성, 자원 사용량 등을 평가하는 것을 목표로 합니다.
- 주요 목적:
- 속도 (Speed): 시스템이 주어진 부하에서 응답 시간을 충족하는지 확인합니다.
- 확장성 (Scalability): 사용자 수와 데이터 부하가 증가할 때 시스템이 이를 처리할 수 있는지를 평가합니다.
- 안정성 (Stability): 긴 시간 동안 부하가 가해질 때도 시스템이 안정적으로 작동하는지 검증합니다.
- 자원 사용량 (Resource Usage): CPU, 메모리, 네트워크 대역폭, 디스크 I/O 등의 사용량이 적절한지 평가합니다.
- 유형:
- 부하 테스트 (Load Testing): 정상적인 조건에서 시스템이 어떻게 동작하는지를 평가합니다.
- 목표: 정해진 사용자 수나 데이터 부하에서 성능을 확인.
- 스트레스 테스트 (Stress Testing): 시스템이 최대 한계를 초과하는 부하에서 어떻게 동작하는지를 확인합니다.
- 목표: 시스템의 안정성과 복구 능력을 평가.
- 내구성 테스트 (Endurance Testing): 장시간 동안 부하가 지속될 때 시스템이 안정적으로 동작하는지를 평가합니다.
- 목표: 메모리 누수와 같은 장기적인 문제 발견.
- 스파이크 테스트 (Spike Testing): 짧은 시간 동안 갑작스러운 부하 증가가 발생했을 때 시스템이 어떻게 반응하는지 확인합니다.
- 목표: 급격한 변화에서의 복구 능력을 검증.
- 용량 테스트 (Capacity Testing): 시스템이 처리할 수 있는 최대 사용자 수 또는 데이터 양을 파악합니다.
- 목표: 최적의 하드웨어 및 네트워크 구성 결정.
- 부하 테스트 (Load Testing): 정상적인 조건에서 시스템이 어떻게 동작하는지를 평가합니다.
- 도구 예: JMeter, LoadRunner, Gatling.
3. 테스트 주기와 전략
테스트 주기
- 계획(Planning): 테스트 범위와 목표 설정합니다.
- 설계(Design): 테스트 케이스 작성합니다.
- 구현(Implementation): 테스트 스크립트 작성합니다.
- 실행(Execution): 테스트 실행 및 결과 확인합니다.
- 평가(Evaluation): 테스트 결과 분석 및 보고합니다.
'IT > CS' 카테고리의 다른 글
비동기 프로그래밍의 장단점 (0) | 2025.04.16 |
---|---|
쿠키와 세션 정리 (0) | 2025.01.03 |
HTTPS 암호화 방식 (0) | 2024.12.30 |