Spring-boot application-test.properties - spring-boot

I am trying to unit test the spring-boot application using junit. I have placed the application-test.properties under src/test/resources. I have a ApplicationConfiguration Class which reads the application.properties.
My test class looks like this
#RunWith(SpringRunner.class)
#SpringBootTest(classes=ApplicationConfiguration.class)
#TestPropertySource(locations = "classpath:application-test.properties")
#ActiveProfiles("test")
public class TestBuilders {
#Autowired
private ApplicationConfiguration properties;
When I try to read the properties, it is always null.
My ApplicationConfiguration Class looks something like this
#Configuration
#ConfigurationProperties
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource(value="file:config.properties", ignoreResourceNotFound =
true)})
public class ApplicationConfiguration{
private xxxxx;
private yyyyy;
I tried all possible ways that I found on google.. No luck. Please help!
Thanks in Advance.

The issue is you don't have #EnableConfigurationProperties on your test class.
When you load the application it start from main class(one which has #SpringBootApplication) where you might have #EnableConfigurationProperties and hence it works when you start the application.
Whereas when you are running the Test with only ApplicationConfiguration class as you have specified here
#SpringBootTest(classes=ApplicationConfiguration.class)
Spring doesn't know that it has to Enable Configuration Properties and hence the fields are not injecting and hence null. But spring is reading your application-test.properties file. This can be confirmed by just injecting the value directly in your test class
#Value("${xxxxx}")
private String xxxxx;
Here the value is injected. But to inject into a class with ConfigurationProperties you need to enable it using #EnableConfigurationProperties
Put #EnableConfigurationProperties on your test class and everythhing works fine.

Related

How Do I Manually Wire A Spring Boot Integration Test?

Normally, I would test the web layer in a Spring project like this:
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SpringBootDemoApplicationTests extends AbstractTestNGSpringContextTests {
#LocalServerPort
int randomServerPort;
#Autowired
private TestRestTemplate restTemplate;
However, I currently have a difficult back end that requires a specific #TestConfiguration class to manually instantiate the test dependencies using beans.
This ultimately means that I can't use the #SpringBootTest annotation as it will try to create conflicting beans and fail to instantiate others.
If I am not using the #SpringBootTest annotation, I can manually create the TestRestTemplate instead of autowiring it, but what do I need to do to start the embedded local server on a random port?
I would still continue using #SpringBootTest, and combine that with using #Profile on your configuration classes.
That way you could have a configuration which is only used during tests, by using #ActiveProfiles on your #SpringBootTest classes. In the same way you can turn other config classes on or off depending on whether you want them to load or not.
For example on your test would have the following
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#ActiveProfiles("unittest")
public class SpringBootDemoApplicationTests extends AbstractTestNGSpringContextTests {
...
}
Then create a configuration class which will instantiate your components the way you want them in test
#Profile("unittest")
#Configuration
public void TestConfiguration {
...
}
And you can use profiles to stop your other configuration class from loading during tests.
#Profile("!unittest")
#Configuration
public void ProdConfiguration {
...
}

(De-)Serializing Spring Boot ConfigurationProperties with Jackson

My spring Boot application uses a class annotated with #Configuration and #ConfigurationProperties:
#Configuration
#ConfigurationProperties(prefix = "my")
#Getter
#Setter
public class MyConfigurationProperties {
#Value("${timeout}")
private int defaultTimeout;
}
Now I'd like to read and update these configuration properties using a (private) REST interface, so I created the following controller.
#RestController
#RequestMapping(path = "config")
public class ConfigController {
final MyConfigurationProperties myConfig;
public ConfigController(MyConfigurationProperties myConfig) {
this.myConfig = myConfig;
}
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MyConfigurationProperties> get() {
return ResponseEntity.ok(myConfig);
}
}
Unfortunately this doesn't seem to work as I get the following exception when calling the endpoint:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.springframework.context.expression.StandardBeanExpressionResolver and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
The JSON response even contains "strange" properties when disabling FAIL_ON_EMPTY_BEANS:
How would I be able to (de-)serialize this configuration class using Jackson?
When removing the annotations #Configuration and #ConfigurationProperties for testing purposes, the serialization works just fine. So it seems to have to do something with the class being a bean?
You are mixing things: configuration properties and autowiring a value. If you want to have a POJO as a configuration property class, drop the #Value annotation. You can also drop #Configuration annotation if you add #EnableConfigurationProperties to your main class (this way all #ConfigurationProperties classes will be automatically detected). If a problem persists, please update the question and show us how the properties prefixed with 'my' look like.

IntelliJ Idea + Could not autowire. No beans of type found

I keep seeing below error in my IntelliJ Idea, however the code works fine during execution.
Could not autowire. No beans of 'PortfolioRequestHandler' type found. less... (Ctrl+F1)
Inspection info:Checks autowiring problems in a bean class.
Sample Code
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#SpringBootTest(classes = {Application.class})
public class PortfolioRequestHandlerTest {
#Autowired
private PortfolioRequestHandler portfolioRequestHandler;
...
...
}
How do I get rid of this? I am using IntelliJ Idea ULTIMATE 2018.2
Are you sure that your Spring beans are wired correctly and that it's an IDE problem?
check if your PortfolioRequestHandler class is annotated with #Service, #Component or #Repository (bean config via component scanning)
otherwise check if your bean is wired in a #Configuration annotated class -> in that case there should be a method that returns an instance of type PortfolioRequestHandler and that's annotated with #Bean
try adding a configuration class (as mentioned in 2.) and add this class to your #SpringBootTest(classes = {...} annotation; see example below
#Configuration
public class CustomBeanConfig {
#Bean
public PortfolioRequestHandler get PortfolioRequestHandler() {
return new PortfolioRequestHandler();
}
}
#SpringBootTest(classes = {Application.class, CustomBeanConfig.class})
have a look at this one, maybe helps: https://stackoverflow.com/a/50267869/150623

Prevent Application / CommandLineRunner classes from executing during JUnit testing

If in your TestCase class there is this annotations:
#SpringApplicationConfiguration(classes = {Application.class})
this will cause the Application.class, implementing the CommandLineRunner interface, to run the required method
public void run(String... args) throws Exception
I still think this is, mostly, a not wanted behaviour, since in your test environment you may not want to launch the entire application.
I have in mind two solution to circumvent this problem:
to remove the CommandLineRunner interface from my Application class
to have a different context for testing
Both this solution requires lot of coding.
Do you have a more convenient solution?
Jan's solution can be achieved easier.
In your test class, activate the "test" profile:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
public class MyFancyTest {}
In your CommandLineRunner set the profile to NOT test:
#Component
#Profile("!test")
public class JobCommandLineRunner implements CommandLineRunner {}
Then you don't have to manually set the profile in the Application.
As mentioned in the spring documentation you can use #ContextConfiguration with a special initializer:
ConfigDataApplicationContextInitializer is an ApplicationContextInitializer that you can apply to your tests to load Spring Boot application.properties files. You can use it when you do not need the full set of features provided by #SpringBootTest
In this example anyComponent is initialized and properties are injected, but run(args) methods won't be executed. (Application.class is my main spring entry point)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class,
initializers = ConfigDataApplicationContextInitializer.class)
public class ExtractorTest {
#Autowired
AnyComponent anyComponent;
#Test
public void testAnyComponent() {
anyComponent.anyMethod(anyArgument);
}
}
You can define a test configuration in the same package as your application that looks exactly the same, except that it excludes beans implementing CommandLineRunner. The key here is #ComponentScan.excludeFilters:
#Configuration
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = CommandLineRunner.class))
#EnableAutoConfiguration
public class TestApplicationConfiguration {
}
Then, just replace the configuration on your test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = TestApplicationConfiguration.class)
public class SomeApplicationTest {
...
}
No CommandLineRunner will be executed now, because they are not part of the configuration.
I'm a bit late to the party, but a reasonable approach is to mark the bean with #ConditionalOnProperty, e.g.
#ConditionalOnProperty(prefix = "job.autorun", name = "enabled", havingValue = "true", matchIfMissing = true)
public CommandLineRunner myRunner() {...}
The following annotation will then disable it in tests:
#SpringBootTest(properties = {"job.autorun.enabled=false"})
If you have a mocking framework installed (e.g. MockMVC) you can create a mock instance of the CommandLineRunner implementation, more or less disabling it:
#MockBean
private TextProcessor myProcessor;
Previous answers didn't work wor me. I ended up using different profiles - example for the init method in Spring Boot:
SpringApplication app = new SpringApplication(AppConfig.class);
app.setAdditionalProfiles("production");
app.run(args);
This is not executed during the tests so we're safe here.
All tests have their own profile "test" (which is useful in many other ways, too):
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
public class MyFancyTest {}
The command-line runner is annotated with the "production" profile so the tests ignore it:
#Component
#Profile("production")
public class JobCommandLineRunner implements CommandLineRunner {}
I solve this by not implementing CommandLineRunner. Just get a bean from the context, and call a method on it, passing argv. That way you will get the same result, and the application won't start automatically when running the tests.

Spring Testing: How to enable auto-scan of beans

For example, now in each test class I have to do
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
I want to get rid of
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
and want Spring to scan all the beans in my project.
How can I do that?
You can do this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTest {
#Test
public void testSomething() {
}
#Configuration
#ComponentScan("basepackage")
public static class SpringConfig {
}
}
By default #ContextConfiguration will look for static inner classes annotated with #Configuration, which is why this set up will just work.
You can get rid of loader param altogether, that is not required
If you have your spring configuration in an xml file you would use something like:
#ContextConfiguration(locations="classpath:applicationContext.xml")
If you use Java Config then you would use
#ContextConfiguration(classes=Config.class)
I used generic names in the above samples, you'll of course need to adapt to your project's configuration.
In both cases Spring's component scanning will need to be enabled for Spring to pickup the annotated classes.
You can also simply add #SpringBootTest if using Spring Boot.
#TestConfiguration
#ComponentScan("basepackage")
public class TestConfig{
}
Adding a config class lets spring to load application context.
This solved this issue for me.

Resources