I have a multi module Spring Boot project with the following structure:
MyAppModule
src/main/java/Application.java
...
IntegrationTests
src/test/java/integrationTest.java
The IntegrationTest module is testing the MyAppModule. The IntegrationTest module does not have a main package. Therefore there is no Spring Application. It has just the test package.
Nevertheless I would like to read in the application.yaml for some properties but I'm not able to because the attributes are always null:
#Configuration
#PropertySource("classpath:application.yaml")
public class IntegrationTest {
#Value("${app.url}")
private String appUrl;
}
Isn't it possible to use the #Value annotation without having a Spring Application (main with SpringApplication.run etc.)?
Why not just #ConfigurationProperties?
#Configuration
#ConfigurationProperties(prefix = "app")
public class IntegrationTest {
private String url;
}
Add Integration tests base package for component scanning in spring configuration.
#ComponentScan("basePackage1,basePackage2....etc")
Thanks for all responses. Solved it with the following code and a SpringBootApplication was necessary.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class IntegrationTest {
#Value("${app.url}")
private String url;
}
Related
I have a Spring Boot Application with the following (simplified) configuration class
#ConfigurationProperties(prefix = "prefix")
#Configuration
public class ConfigProperties {
#NotNull
public Duration snapshotOffset;
}
My code is working, but I would like know how I can write unit tests for the binding process with different property files as input?
You can configure test properties files by using the locations or value attribute of the TestPropertySource annotation :
//Typically, #TestPropertySource will be used in conjunction with #ContextConfiguration.
#ContextConfiguration
#TestPropertySource("/test.properties")
public class Test {
// class body...
}
In my multimodule project I have integration tests as seperate module. That tests have application jar added as dependency. Is it possible to override application bean definition from integration tests?
In application I have following Bean (standard java mail sender configuration)
#Configuration
public class MailConfiguration {
#Bean
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
//standard mail configuration using properties
}
}
Now all my integration tests extends BaseIntegrationTest that loads test configuration classess
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { AppTestConfiguration.class, MailTestConfiguration.class})
public class BaseIntegrationTest {
}
And finally in my MailTestConfiguration I define another JavaMailSender
#Primary
#Bean
#Profile(TestProfiles.MAIL_GREEN_SMTP)
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost("localhost");
javaMailSender.setPort(3025);
return javaMailSender;
}
It is working when I run the tests from application itself. When I run the tests from another module the bean is not overriden.
I am aware that AppConfiguration class defined inside application cannot component scan the integration tests config classes so I also load AppTestConfiguration.
#Configuration
#ComponentScan(basePackages = {"..."})
public class AppTestConfiguration extends AppConfiguration {
}
How to make it work?
Two things you should check:
Is the right Spring profile enabled when you run the tests from another module?
Is the given configuration in the scan path when you run the tests from another module?
Sure I messed up with profiles. In my BaseIntegrationTest I defined active profile based on configuration. I also printed which profile gets resolved there (correct profile name was printed)
#BeforeClass
public static void init() {
System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, ProfileResolver.getActiveProfiles());
}
After you convinced me that it should work I rechecked the config and found that I also added spring.profiles.active in properties. After deleting this config everything work as expected. The other way is to use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME instead of AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME
I have a Spring Boot project, version 1.5.4, with a MongoDb configuration class:
#Configuration
public class MongoConfig {
#Value("${spring.data.mongo.client.uri:mongodb://localhost:27017/database}")
private String mongoURI;
#Bean
public MongoDbFactory mongoFactory() throws UnknownHostException{
return new SimpleMongoDbFactory(new MongoClientURI(mongoURI));
}
#Bean
public MongoTemplate mongoTemplate() throws UnknownHostException, MongoException{
return new MongoTemplate(mongoFactory());
}
}
In my integration test i want use Embedded Mongo (https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo).
The problem is that the MongoDb configuration class start before the initialitation of Embedded mongo and try to connect to the database, so my test fail. If i remove the MongoConfig class, all test work well.
How can i exclude it only in my test execution?
Exclude the MongoDB autoconfiguration by using below annotation over your test class.
#EnableAutoConfiguration(exclude={MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class})
Then in the same path as your test class create a configuration class and define your mongo bean over there. This will get picked up during application start up
**#Configuration
public class MockConfigurations {
#Bean
#Primary
public MongoTemplate getMongoTemplate() {
//define your bean
return mongoTemplate;
}
}**
Please refer the answers here. It has two ways of excluding configurations.
Spring boot: apply #Configuration to certain package only
Update 1:
Alternatively, the most efficient way that I can think of is to use Spring profiles and load the profile for the tests
Define your TestConfiguration class and import it your test class.
#RunWith(SpringRunner.class)
#SpringBootTest
#Import(MyTestConfiguration.class)
public class MyTests {
#Test
public void exampleTest() {
...
}
}
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-detecting-config
Update 2:
For EmbeddedMongoAutoConfiguration please refer the detailed answers here.
How do you configure Embedded MongDB for integration testing in a Spring Boot application?
I solved it with this configuration on my test class:
#RunWith(SpringRunner.class)
#ComponentScan({"it.app.server.dal","it.app.server.listener"})
#DataMongoTest() //mongoDB
public class ListenerTests {
...
}
The annotation #DataMongoTest() load my Embbedded MongoDb and with #ComponentScan i can just load the services and repositories wich i need in my test.
I have configured my application using #Configuration annotated classes in the config package:
main
java
com.ourcompany
config
PersistenceConfig
JacksonConfig
persistence
...
Application
test
java
com.ourcompany
persistence
PersistenceTest
The configuration gets picked up by the Application class without a problem:
#SpringBootApplication
public class Application {
public static void main( String[] args ) {
SpringApplication.run( Application.class, args );
}
}
However, the Test class:
#RunWith(SpringRunner.class)
#DataMongoTest
public class PersistenceTest {
...
}
does not pick up the configuration, unless I specify the name of the configuration class in the annotation:
#SpringBootTest(classes = PersistenceConfig.class)
I find this quite unintuitive, since I have to explicitly list all my config classes.
What is the idiomatic way to share the configuration in Spring Boot?
EDIT
In the end the problem was with including both #DataMongoTest and #SpringBootTest at the same time. Removing the #DataMongoTest and annotating the test class as:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
public class PersistenceTest {
...
}
Solved the problem. However, the question as to what is the best practice remains.
I have a SpringBoot main application, as well as a separate Maven module project that compiles as a separate Jar. The module has a Spring config class annotated with #Configuration, which I want to get loaded, when the main app loads.
Apparently, this does not happen out of the box (by just including the module to the main app). What else do I need to do, to get the module configuration class also get loaded by the main app?
The easiest way is to scan the package that the #Configuration class is in.
#ComponentScan("com.acme.otherJar.config")
or to just load it as a spring bean:
#Bean
public MyConfig myConfig() {
MyConfig myConfig = new MyConfig ();
return myConfig;
}
Where MyConfig is something like:
#Configuration
public class MyConfig {
// various #Bean definitions ...
}
See docs
#ComponentScan annotation will scan all classes with #Compoment or #Configuration annotation.
Then spring ioc will add them all to spring controlled beans.
If you want to only add specific configurations, you can use #import annotation.
example:
#Configuration
#Import(NameOfTheConfigurationYouWantToImport.class)
public class Config {
}
#Import Annotation Doc