학습
Java 고급 테스트 기법 (Mocking)
Java 고급 테스트 기법 (Mocking) — 고급
고급 테스트 기법 (Mocking)
1. 도입 (왜 배워야 하는가)
Mocking은 소프트웨어 테스트에서 의존성을 가상의 객체로 대체하는 기법입니다. 이 기법은 특히 외부 시스템(예: 데이터베이스, 웹 서비스)과의 상호작용이 필요한 경우에 중요합니다. Mocking을 사용하면 테스트 환경을 통제할 수 있어, 테스트의 신뢰성과 속도를 높일 수 있습니다.
Mocking을 모르면, 다음과 같은 문제가 발생할 수 있습니다:
- 의존성이 있는 외부 시스템이 불안정하여 테스트가 자주 실패함.
- 테스트 환경을 설정하는 데 많은 시간과 노력이 소모됨.
- 특정 기능에 대한 테스트가 불가능해져, 최종 제품의 품질이 저하됨.
2. 핵심 개념 설명
Mocking은 실제 객체 대신에 가짜 객체(mock object)를 사용하여 테스트를 수행하는 기법입니다. 이를 통해 특정 상황을 시뮬레이션하고, 코드의 특정 부분에 대한 테스트를 독립적으로 수행할 수 있습니다.
실생활 비유
Mocking은 요리를 할 때 필요한 재료가 없어 요리를 시도하지 못하는 상황과 비슷합니다. 실제 재료가 없더라도, 비슷한 대체 재료를 사용하여 요리의 결과를 평가할 수 있습니다.
| 용어 | 설명 |
|---|---|
| Mock Object | 실제 객체 대신 사용되는 가짜 객체 |
| Stub | 특정 메서드 호출에 대해 고정된 값을 반환하는 객체 |
| Spy | 실제 객체의 행동을 추적하는 객체 |
3. 기본 코드 예제
아래는 Mockito를 사용하여 간단한 Mock 객체를 만드는 예제입니다. Mockito는 Java에서 가장 널리 사용되는 Mocking 프레임워크 중 하나입니다.
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
class Calculator {
public int add(int a, int b) {
return a + b;
}
}
class CalculatorService {
private final Calculator calculator;
public CalculatorService(Calculator calculator) {
this.calculator = calculator;
}
public int calculateSum(int a, int b) {
return calculator.add(a, b);
}
}
public class CalculatorServiceTest {
@Test
public void testCalculateSum() {
// Mocking Calculator 객체 생성
Calculator mockCalculator = Mockito.mock(Calculator.class);
// Mock 객체의 add 메서드의 동작 정의
Mockito.when(mockCalculator.add(2, 3)).thenReturn(5);
// CalculatorService에 Mock 객체 주입
CalculatorService service = new CalculatorService(mockCalculator);
// 테스트 실행
int result = service.calculateSum(2, 3);
assertEquals(5, result);
}
}
실행 결과:
테스트 성공
코드 설명:
Calculator클래스는 두 수를 더하는 단순한 메서드를 가지고 있습니다.CalculatorService클래스는Calculator객체를 주입받아,calculateSum메서드를 통해 두 수의 합을 계산합니다.CalculatorServiceTest클래스에서 Mockito를 사용하여Calculator의 Mock 객체를 생성합니다.- Mock 객체의
add메서드가 호출될 때, 고정된 값을 반환하도록 설정합니다. CalculatorService에 Mock 객체를 주입하고,calculateSum메서드를 호출하여 결과를 검증합니다.- Mocking은 의존성을 가짜 객체로 대체해 테스트의 신뢰성을 높입니다.
- Mockito는 Java에서 가장 많이 사용되는 Mocking 프레임워크입니다.
- Mock 객체의 동작을 정의하는 것이 중요합니다.
- 단위 테스트와 통합 테스트의 차이
- TDD(테스트 주도 개발) 기법
- BDD(행위 주도 개발) 기법
4. 실전 활용 예제
예제 1: 쇼핑몰 장바구니 구현
쇼핑몰에서 장바구니에 상품을 추가하는 기능을 테스트할 때, 실제 데이터베이스에 접근하지 않고 Mocking을 사용합니다.
class CartService {
private final ProductService productService;
public CartService(ProductService productService) {
this.productService = productService;
}
public int addItemToCart(int productId) {
return productService.getProductPrice(productId);
}
}
// 테스트
@Test
public void testAddItemToCart() {
ProductService mockProductService = Mockito.mock(ProductService.class);
Mockito.when(mockProductService.getProductPrice(1)).thenReturn(1000);
CartService cartService = new CartService(mockProductService);
int price = cartService.addItemToCart(1);
assertEquals(1000, price);
}
예제 2: 외부 API 호출
외부 API를 호출하는 서비스의 테스트를 Mocking을 통해 수행할 수 있습니다.
class ApiService {
public String fetchData() {
// 실제 API 호출 코드
return "real data";
}
}
// 테스트
@Test
public void testFetchData() {
ApiService mockApiService = Mockito.mock(ApiService.class);
Mockito.when(mockApiService.fetchData()).thenReturn("mock data");
assertEquals("mock data", mockApiService.fetchData());
}
5. 흔한 실수와 주의사항
실수 1: Mock 객체를 사용하지 않고 실제 객체를 사용
// 잘못된 예
CalculatorService service = new CalculatorService(new Calculator());
→ 실제 객체를 사용하면 테스트가 특정 구현에 의존하게 되어, 테스트의 유연성이 떨어집니다.
실수 2: Mock 객체의 동작을 정의하지 않음
// 잘못된 예
Mockito.when(mockCalculator.add(2, 3)); // 반환값이 정의되지 않음
→ 호출 시 NullPointerException이 발생할 수 있습니다.
올바른 코드
Mock 객체의 동작을 반드시 정의해 주어야 합니다.
6. 정리
다음에 학습하면 좋은 주제: