2 min to read
ApplicationEventPublisher를 테스트하려면?
ApplicationEventPublisher를 테스트하려면?
ApplicationEventPublisher를 test하려면?
applicationEventPublisher.publishEvent() 메소드가 호출되는 횟수를 카운팅하는 test code를 작성하려는데 아래와 같은 오류가 발생하면서 제대로 test 할 수 없는 상황에 직면했다.
org.springframework.context.ApplicationEventPublisher#0 bean.publishEvent(
<any com.jd.application.ProductCommand>
);
-> at com.jd.application.service.ProductCommandTest.test(ProductCommandTest.java:74)
Actually, there were zero interactions with this mock.
일반적으로 ApplicationEventPublisher를 테스트할 떄 보통 @SpyBean 혹은 @MockBean으로 주입하여 test code를 작성하면 정상적으로 test code가 동작하지 않는다.
왜냐하면 @ExtendWith(SpringExtension.class) 형태로 특정 객체의 TEST CODE를 작성할 경우,
ApplicationEventPublisher는 외부에서 주입된 빈이 아닌 spring context 자체에서 다루는 빈이기 때문에 일반적인 @MockBean 형태로 test code에서 활용할 수 없다.
따라서 아래와 같이 직접 test mock bean을 직접 생성하여 주입받아 사용해야 한다.
- 실행 코드
@Service
@RequiredArgsConstructor
public class ProductCommand implements ProductUseCase {
private final ProductRepository productRepository;
private final ApplicationEventPublisher eventPublisher;
@Override
@Transactional
public void save(ProductEvent event) {
Product product = Product.create(event);
if (!productRepository.existsById(event.getId())) {
eventPublisher.publishEvent(ProductHistoryEvent.of(event.getUserId()));
}
if (!ObjectUtils.isEmpty(event.getName())) {
eventPublisher.publishEvent(ProductHistoryEvent.of(event.getUserId()));
}
if (!ObjectUtils.isEmpty(event.getAmount())) {
eventPublisher.publishEvent(ProductHistoryEvent.of(event.getUserId()));
}
productRepository.save(product);
}
}
- 테스트 코드
@ExtendWith(SpringExtension.class)
@Import(ProductCommand.class)
class ProductCommandTest {
@SpyBean
private ProductCommand productCommand;
@MockBean
private ProductRepository productRepository;
@Autowired
private ApplicationEventPublisher eventPublisher;
@Test
public void test() {
//given
Product product = mock(Product.class);
given(productRepository.existsById(any())).willReturn(false);
given(product.getName()).willReturn(null);
given(product.getId()).willReturn("ID1");
//when
productCommand.save(product);
//then
verify(eventPublisher, times(1)).publishEvent(any(Product.class));
verify(productRepository, times(1)).save(any());
}
@TestConfiguration
static class MockitoPublisherConfiguration {
@Bean
@Primary
ApplicationEventPublisher publisher() {
return mock(ApplicationEventPublisher.class);
}
}
}
Comments