적합한 테스트 가이드
레이어(layer)별로 사용하기 적합한 방식의 테스트 가이드에 대해 알아보겠습니다.
그 중에 '서비스 객체'를 테스트하는 방법을 알아보겠습니다.
1️⃣ ProductService 메서드 테스트
class ProductServiceTest {
private final ProductRepository productRepository
= Mockito.mock(ProductRepository.class);
private ProductServiceImpl productService;
@BeforeEach
public void setUpTest() {
productService = new ProductServiceImpl(productRepository);
}
@Test
void getProductTest() {
//given
Product product = Product.builder()
.number(123L)
.name("pen")
.price(1000)
.stock(1234)
.build();
Mockito.when(productRepository.findById(123L))
.thenReturn(Optional.of(product));
//when
ProductResponseDto responseDto
= this.productService.getProduct(123L);
//then
Assertions.assertEquals(responseDto.getNumber(), product.getNumber());
Assertions.assertEquals(responseDto.getName(), product.getName());
Assertions.assertEquals(responseDto.getPrice(), product.getPrice());
Assertions.assertEquals(responseDto.getStock(), product.getStock());
verify(productRepository).findById(123L);
}
}
- 단위 테스트를 위해서는 외부 요인을 모두 배제하도록 작성해야한다.(@SpringBootTest, @WebMvcTest 등 선언 x)
- Mockito.mock() 메서드를 통해 Mock 객체로 ProductRepository를 주입받았다.
- 해당 객체를 기반으로 테스트 전에 ProductService 객체를 초기화하여 사용한다.
- 해당 테스트 코드는 Given-When-Then 패턴을 기반으로 작성되었다.
Given-When-Then 패턴
- Given 구문 : 테스트 사용될 Product 엔티티 객체 생성 및 ProductRepository의 동작에 대한 리턴 값을 설정한다.
- When 구문 : 테스트하고자 하는 ProductService의 getProduct() 메서드를 호출해서 동작을 테스트한다.
- Then 구문 : 테스트에서 리턴받은 responseDto의 값을 Assertion 을 통해 값을 검증함으로 테스트의 목적을 확인하고, verify() 메서드로 검증보완 및 부가 검증을 시도한다.
2️⃣ ProductService 메서드 테스트
class ProductServiceTest {
private final ProductRepository productRepository
= Mockito.mock(ProductRepository.class);
private ProductServiceImpl productService;
@BeforeEach
public void setUpTest() {
productService = new ProductServiceImpl(productRepository);
}
@Test
void saveProductTest() {
//given
Mockito.when(productRepository.save(any(Product.class)))
.then(returnsFirstArg());
//when
ProductResponseDto responseDto
= productService.saveProduct(new ProductDto("pen", 1000, 1234));
//then
Assertions.assertEquals(responseDto.getName(), "pen");
Assertions.assertEquals(responseDto.getPrice(), 1000);
Assertions.assertEquals(responseDto.getStock(), 1234);
verify(productRepository).save(any());
}
}
- any()
- Mockito의 ArgumentMatchers에서 제공하는 메서드이다.
- Mock 객체의 동작을 정의하거나 검증하는 단계의 조건이다.
- 특정 매개변수의 전달을 설정하지 않고 메서드의 실행만을 확인하거나 좀 더 큰 범위의 클래스 객체를 매개변수로 전달받는 등의 상황에 사용한다.
- ex) any(Product.class)
- 일반적으로 given()으로 정의된 Mock 객체의 메서드 동작 감지는 매개변수의 비교를 통해 이루어진다.
- 레퍼런스 변수의 비교는 주소값으로 이뤄지기 때문에 any()를 사용해 클래스만 정의하는 경우도 있다.
3️⃣ ProductService 메서드 테스트(@MockBean 어노테이션 이용)
@ExtendWith(SpringExtension.class)
@Import({ProductServiceImpl.class})
class productServiceTest2 {
@MockBean
ProductRepository productRepository;
@Autowired
ProductService productService;
//...이하 생략...
}
- @MockBean을 사용하는 방식
- 스프링에 Mock 객체를 등록해서 주입받는 형식이다.
- 스프링을 사용하지 않는 Mock 객체를 직접 생성하는 방식이 더 빠르게 동작한다.
- @ExtendWith(SpringExtension.class)
- JUnit5 테스트에서 스프링 테스트 컨텍스트를 사용하도록 설정한다.
- @Import
- @AutoWired 어노테이션을 주입받는 ProductService를 주입받기 위해 사용한다.
반응형
'TEST > JUnit' 카테고리의 다른 글
단위 테스트 방법 [part 3 : 리포지토리(Repository)] (0) | 2023.11.08 |
---|---|
단위 테스트 방법 [part 1 : 컨트롤러(Controller)] (0) | 2023.11.08 |
JUnit 테스트 코드의 설명과 예제 (0) | 2023.11.07 |
댓글