Search code examples
spring-bootspring-boot-test

@WebMvcTest doesn't see @Value Annotation


I created a single MessageSourceConfig like below:

@Configuration
public class MessageSourceConfig {

    @Value("${spring.messages.basename}")
    private String[] basenames;

    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();

        messageSource.setBasenames(basenames);
        messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());

        return messageSource;
    }
}

and typical controller like TodoController:

@RestController
@RequestMapping("api/v1/todos")
@RequiredArgsConstructor
public class TodoController {
    private final GetTodosUseCaseHandler getTodosUseCaseHandler;

    @GetMapping("all")
    public ResponseEntity<List<TodoResponseDto>> getAllTodos() {
        List<TodoAggregate> todos = getTodosUseCaseHandler.handle();
        return ResponseEntity.ok(TodoMapper.INSTANCE.aggregateListToTodoResponseDtoList(todos));
    }
}

and finally created a ControllerTest with WebMvcTest:

@WebMvcTest(controllers = TodoController.class)
@ContextConfiguration(classes = {MessageSourceConfig.class, TodoController.class},
        initializers = ConfigDataApplicationContextInitializer.class)
class TodoControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private GetTodosUseCaseHandler getTodosUseCaseHandler;

    @MockBean
    private CreateTodoUseCaseHandler createTodoUseCaseHandler;

    private static final Long TODO_ID_1 = 1L;

    @Test
    void getAllTodos_success() throws Exception {
        List<TodoAggregate> results = List.of(createAggregate());

        when(getTodosUseCaseHandler.handle()).thenReturn(results);

        mockMvc.perform(get("/api/v1/todos/all"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$").isArray())
                .andExpect(jsonPath("$.[0].id", is(TODO_ID_1.intValue())))
                .andExpect(jsonPath("$", hasSize(1)));

        verify(getTodosUseCaseHandler).handle();
    }
}

While testing my application, when I try to reach messageSource -> basenames param doesn't work properly. basenames return like ${spring.messages.basename} is there any suggestion?

spring.messages.basename=messages

Expexted Output for ${spring.messages.basename} is messages but it was ${spring.messages.basename}


Solution

  • Interesting but @Value doesn't work for this case. Find two different solutions:

    Solution 1: (Using environment)

    @Configuration
    @RequiredArgsConstructor
    public class MessageSourceConfig {
        private final Environment environment;
    
        @Bean
        public ReloadableResourceBundleMessageSource messageSource() { 
            String[] basenames = environment.getProperty("spring.messages.basename", String[].class);
            ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    
            messageSource.setBasenames(basenames);
            messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
    
            return messageSource;
        }
    }
    

    Solution 2: (Using @ConfigurationProperties)

    @Configuration
    @RequiredArgsConstructor
    public class MessageSourceConfig {
    
        @Bean
        @ConfigurationProperties(
            prefix = "spring.messages"
        )
        public MessageSourceProperties sourceProperties() {
            return new MessageSourceProperties();
        }
    
        @Bean
        public ReloadableResourceBundleMessageSource messageSource(MessageSourceProperties sourceProperties) { 
            String[] basenames = StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(sourceProperties.getBasename()));
            ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    
            messageSource.setBasenames(basenames);
            messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
    
            return messageSource;
        }
    }