@WebMvcTest with @Autowire Constructor in WebConfig

Viewed 293

I want to test a Spring RestController. There is a Web Config in this project with an @Autowired Constructor, which should initialize a ConfigurationPropertie with environment variables from the application-{environment}.yml-file. Since I have implemented this, my Application runs correctly but the WebMvcTest for the Controller is failing with following error:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webConfig': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.project.onlineDate.shared.entity.OriginAllowedUrisProperties' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Code Part 1: EnvironmentPropertie Class

@Configuration
@Component
@ConfigurationProperties(prefix = "origins")
public class OriginAllowedUrisProperties {

    String[] allowedUris;

    //Getter and Setter
}

Code Part 2: WebConfig

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final
    OriginAllowedUrisProperties originAllowedUrisProperties;

    @Autowired
    public WebConfig(OriginAllowedUrisProperties originAllowedUrisProperties) {
        this.originAllowedUrisProperties = originAllowedUrisProperties;
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins(
                        originAllowedUrisProperties.getAllowedUris());
    }

}

Code Part 3: WebMvcTest

@ExtendWith(SpringExtension.class)
@WebMvcTest(OnlineDateController.class)
class TestOnlineDateController {

    [...]

    @MockBean
    private OnlineDateService onlineDateService;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void testGetOnlineDate() throws Exception {

        when(onlineDateService.findOnlineDates().thenReturn(
                Collections.singletonList(new OnlineDate()));

        mockMvc.perform(
                get("/onlineDates")
                        .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(JSON_ONLINE_DATE_MATCHER)
                .andDo(print());
    }
}

Attemps for fix

I tried for example to declare a Context Configuration at Class Level with @ContextConfiguration(classes = {WebConfig.class}) and I´ve tried to exclude the configuration with @Filter declaration. I have also tried a lot with the OriginAllowedUrisProperties.class to load environment variables in another way, but nothing worked. What am I missing? Do you have an Idea? Thanks in advance.

1 Answers

After struggling to this I want to share my Solution. Hopefully this will help others who face the same challenge.After many attempts I have now solved it a bit differently.

My Solution:

I pulled the bean declaration out of the entity and made it directly in the web controller. This information is not needed anywhere else in the project and therefore I can leave all test classes as they are. Here are the code components, which I have changed in contrast to above.

Code Part 1: EnvironmentProperty Class

  • Removed Spring Annotations
public class OriginAllowedUrisProperties {

    String[] allowedUris;

    //Getter and Setter
}

Code Part 2: WebConfig

  • Bind the @ConfigurationProperties on a @Bean method in WebConfig to bind externalized properties to the OriginAllowedUrisProperties
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    @ConfigurationProperties(prefix = "origins")
    public OriginAllowedUrisProperties originAllowedUrisProperties() {
        return new OriginAllowedUrisProperties();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins(originAllowedUrisProperties().getAllowedUris());
    }

}
Related