Spring boot: @ConfigurationProperties not satisfied on test

心已入冬 提交于 2020-01-13 07:11:14

问题


I'm getting this exception on my test excution:

UnsatisfiedDependencyException: Error creating bean with name 'net.gencat.transversal.espaidoc.mongo.GridFSTest': Unsatisfied dependency expressed through field 'resourceProperties'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.gencat.transversal.espaidoc.ResourcesConfigProperties' available: expected at least 1 bean which qualifies as autowire candidate.

So, I think message is so clear enough: ResourcesConfigProperties is not satisfied.

My test:

RunWith(SpringRunner.class)
@SpringBootTest()
public class GridFSTest {

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private ResourcesConfigProperties resourceProperties;

    public URL getHugeResource() {
        try {
            return Paths
                .get(this.resourceProperties.getHuge())
                .toUri()
                .toURL();
        } catch (MalformedURLException e) {
            return null;
        }
    }

    @Test
    public void storeHugeFile() throws IOException {
        URL resource = this.getHugeResource();

        this.gridFsTemplate.store(
            resource.openStream(),
            resource.getPath(),
            "mime"
        );
    }
}

and ResourcesConfigProperties is:

@ConfigurationProperties(prefix = "files")
public class ResourcesConfigProperties {

    private String huge;

    /**
     * @return the huge
     */
    public String getHuge() {
        return huge;
    }

    /**
     * @param huge the huge to set
     */
    public void setHuge(String huge) {
        this.huge = huge;
    }

}

into my src/test/resources I have my application.properties file:

files.huge: /home/jcabre/Downloads/1GB.zip

Any ideas?

EDIT

Main Spring boot application:

@SpringBootApplication(
    //scanBasePackages = { "cat.gencat.ctti.canigo.arch.web.rs" },
    exclude = JmxAutoConfiguration.class
)
@EnableConfigurationProperties({
    ApiProperties.class,
    FileStoreProperties.class
})
@Import(RedisConfiguration.class)
public class ApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }
}

回答1:


TL;DR:

It is happening, because the @ConfigurationProperties are not managed by the application context you build in tests, although they will be load when the application launches, because you have @EnableConfigurationProperties on your app main class.

@EnableConfigurationProperties on main class only affect the application context you have when you bootRun, but not that in a @SpringBootTest. The application context you build in tests could be, under many circumstances, distinct with that of bootRun, just like in your case.

You can add @Component to make the context be aware of it, both in gradle bootRun and in gradle test. It's the easiest way, but not 100% the suggested way.


More proper way with details if you have time

Instead, you can add @EnableConfigurationProperties({Config1.class, Config2.class}) in a @SpringBootTest, to inject only some of the configuration properties class into the context, to avoid injection overhead.

It would be like:

//@RunWith(SpringRunner.class) // for JUnit4 in Spring
@ExtendWith(SpringExtension.class) // for JUnit5 in Spring. 
@SpringBootTest
@EnableConfigurationProperties({
        ResourcesConfigProperties.class,
})
@Data
public class ConfigsTest {

    @Autowired
    private ResourcesConfigProperties resourceConfigProperties;

    ...

}

Better yet, you can use @SpringBootTest(classes={}): classes within {} are those you want the application context of @SpringBootTest to manage(creation, initialization, loading properties from yaml files, and so on). Then you don't have to load all the context, but only part of it.

You can group all classes of @ConfigurationProperties in one class of @Configuration, and put it in the classes={} of @SpringBootTest, instead of repeating this list of @ConfigurationProperties everywhere. Something like:

//@RunWith(SpringRunner.class) // for JUnit4 in Spring
@ExtendWith(SpringExtension.class) // for JUnit5 in Spring. 
@SpringBootTest(classes = {
    TestConfiguration.class
})
@Data
public class ConfigsTest {

    @Autowired
    private ResourcesConfigProperties resourceConfigProperties;


    ...

}

TestConfiguration.java:

@EnableConfigurationProperties({
        ResourcesConfigProperties.class,
})
@Configuration
public class TestConfiguration {
}



回答2:


You need to add ResourcesConfigProperties to your EnableConfigurationProperties annotation in the main spring boot class, this will load and create a bean out of the ResourceConfigProperties for you

You could also add @Component to your ResourceConfigProperties if you do not want to add it to the EnableConfigurationProperties annotation.

When using the SpringBootTest or any slice test it will use whatever is annotated on, or beans defined within the main SpringBootApplication within the test context.




回答3:


You also need to annotate ResourcesConfigProperties class with @Configuration as below, otherwise it will not create a bean of this class in the spring container.

@Configuration
@ConfigurationProperties(prefix = "files")
public class ResourcesConfigProperties {

    private String huge;

    /**
     * @return the huge
     */
    public String getHuge() {
        return huge;
    }

    /**
     * @param huge the huge to set
     */
    public void setHuge(String huge) {
        this.huge = huge;
    }

}


来源:https://stackoverflow.com/questions/52605568/spring-boot-configurationproperties-not-satisfied-on-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!