Published on

Spring Webflux에서 MessageSource 테스트

Spring Webflux에서 MessageSource 테스트

이번에는 앞서 만든 BindErrorMessageConverter를 테스트를 해볼 생각입니다.


@Component
@RequiredArgsConstructor
public class BindingErrorMessageConverter {

    private final MessageSource messageSource;

    public String getMessage(final String[] codes,
                             final Object[] args,
                             final String defaultMessage) {

        return Arrays.stream(codes)
                .map(code -> createMessageOrNull(code, args))
                .filter(Objects::nonNull)
                .findFirst()
                .orElse(defaultMessage);
    }

    private String createMessageOrNull(final String code, final Object[] args) {

        try {
            return messageSource.getMessage(
                    code,
                    args,
                    LocaleContextHolder.getLocale()
            );
        } catch (NoSuchMessageException e) {
            return null;
        }
    }
}

그런데 여기 보면 MessageSource를 주입받아 사용하고 있는데, 이는 Spring Boot에서 자동으로 생성해준 빈이 주입되게 됩니다.

BindingErrorConverter 단위 테스트를 하는데 통합테스트를 실행 시키는 것은 비효율적이라 생각이 들었습니다.

그래서 MessageSource직접 만들어 주기로 하였습니다.

NotBlank=빈값은 안됩니다.
Min={0} 이상만 허용 됩니다.
Min.numberDTO.number=NumberDTO의 number는 {0} 이상만 허용합니다.

MessageSource 단위 테스트

우선 그 전에 통합테스트를 통해 MessageSource에 잘 주입되는지 부터 확인해 보겠습니다.


@SpringBootTest
public class MessageSourceTest {

    @Autowired
    private MessageSource messageSource;

    @Test
    void messageProperties의_값을_정상적으로_읽어온다() {
        final String message = messageSource.getMessage(
                "NotBlank",
                null,
                "빈값은 안돼요",
                Locale.getDefault()
        );

        Assertions.assertThat(message).isEqualTo("빈값은 안됩니다.");
    }

}

정상적으로 테스트가 통과합니다.

MessageSource 직접 만들기

public class MessageSourceCreator {

    public static MessageSource messageSource() {
        final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:/messages");
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setFallbackToSystemLocale(false);
        return messageSource;
    }
}

위 처럼 경로를 설정하면 messages.properties에 있는 값으로 MessageSource를 만들어 줍니다.

BindingErrorMessageConverter 테스트 하기

public class BindingErrorMessageConverterTest {

    private BindingErrorMessageConverter bindingErrorMessageConverter =
            new BindingErrorMessageConverter(MessageSourceCreator.messageSource());

    private MessageCodesResolver messageCodesResolver = new DefaultMessageCodesResolver();


    @Test
    void codes와_args를_넣어_해당하는_message를_가져온다() {
        // Given
        final String[] codes = messageCodesResolver.resolveMessageCodes(
                "NotBlank",
                "stringDTO",
                "str",
                String.class
        );

        // When
        final String message = bindingErrorMessageConverter.getMessage(
                codes,
                null,
                "공백일 수 없음"
        );

        // Then
        Assertions.assertThat(message).isEqualTo("빈값은 안됩니다.");
    }

    @Test
    void 우선순위_높은_code의_메세지를_가져온다() throws Exception {
        // Given
        final String[] codes = messageCodesResolver.resolveMessageCodes(
                "Min",
                "numberDTO",
                "number",
                Integer.class
        );

        // When
        final String message = bindingErrorMessageConverter.getMessage(
                codes,
                new Object[]{1},
                "1보다 커야함"
        );

        // Then
        Assertions.assertThat(message).isEqualTo("NumberDTO의 number는 1 이상만 허용합니다.");
    }

    @Test
    void 일치하는_code가_존재하지_않으면_defaultMessage를_가져온다() throws Exception {
        // Given
        final String[] codes = messageCodesResolver.resolveMessageCodes(
                "AAA",
                "numberDTO",
                "number",
                Integer.class
        );
        final String defaultMessage = "1보다 커야함";

        // When
        final String message = bindingErrorMessageConverter.getMessage(
                codes,
                new Object[]{1},
                defaultMessage
        );

        // Then
        Assertions.assertThat(message).isEqualTo(defaultMessage);
    }

}

위 에서 만든 MessageSourceBindingErrorMessageConverter를 생성한 뒤 테스틀를 해줍니다.