실제 객체를 만들기에는 비용과 시간이 많이 들거나 의존성이 크게 걸쳐져 있어서 테스트 시 제대로 구현하기 어려울 경우 가짜 객체를 만들어서 사용하는 기술입니다.
비즈니스 로직 클래스
public class SimpleService {
private SimpleDataRepository simpleDataRepository;
public void setSimpleDataRepository(SimpleDataRepository simpleDataRepository) {
this.simpleDataRepository = simpleDataRepository;
}
public int calculateSumUsingDataService() {
int sum = 0;
int[] data = simpleDataRepository.findAll();
for(int value: data) {
sum += value;
}
return sum;
}
}
리포지토리 인터페이스
public interface SimpleDataRepository {
int[] findAll();
}
Test Stub를 통해서 테스트
class SimpleDataRepositoryStub implements SimpleDataRepository {
@Override
public int[] findAll() {
return new int[] {1, 2, 3};
}
}
public class SimpleServiceStubTests {
@Test
public void calculateSumUsingDataService_basic() {
SimpleService simpleService = new SimpleService();
simpleService.setSimpleDataRepository(new SimpleDataRepositoryStub());
int actualResult = simpleService.calculateSumUsingDataService();
int expectedResult = 6;
assertEquals(expectedResult, actualResult);
}
}
여기서 Test Stub이란, 필요한 인터페이스에 대한 구현 객체로 마치 실제로 동작하는 것처럼 보이게 만들어 놓은 객체입니다. 객체의 특정 상태를 가정해서 만들어 특정 값을 리턴해 주거나 특정 메시지를 출력해 주는 작업을 주로 하게 됩니다. 그러나 특정 상태를 가정해서 Hard Coding 된 형태이기 때문에 로직에 따른 값의 변경은 테스트 할 수 없습니다.
Mock Object를 통해서 테스트
public class SimpleServiceMockTests {
@Test
public void calculateSumUsingDataService_basic() {
SimpleService simpleService = new SimpleService();
// 1. Create mock
SimpleDataRepository simpleDataRepositoryMock = mock(SimpleDataRepository.class);
// 2. Specify mock -> when -> then
when(simpleDataRepositoryMock.findAll()).thenReturn(new int[] {1, 2, 3});
simpleService.setSimpleDataRepository(simpleDataRepositoryMock);
int actualResult = simpleService.calculateSumUsingDataService();
int expectedResult = 6;
assertEquals(expectedResult, actualResult);
}
}
여기서 Mock Object
란, 테스트하고자 하는 코드에서 실제로 구현하기 어려운 객체들을 대신하여 동작하기 위해 만들어진 객체입니다. 테스트 시 Mock Object의 미리 정의된 결과를 통해서 테스트를 수월하게 진행할 수 있게 됩니다.