Do not want to load application.yml when testing with Spring Boot - spring-boot

How can I tell Spring to load only application-test.yml and not application.yml file ?
I have a config class:
#ActiveProfiles("test")
#SpringBootConfiguration
public class MongoTestConfig {
#Autowired
MongoOperations operations;
...
}
And a test class:
#RunWith(SpringRunner.class)
#DataMongoTest
#SpringBootTest(classes = MongoTestConfig.class)
public class TagDefinitionRepositoryTest {
...
#Test
....
}
I've tried to add :
#TestPropertySource(locations = {"classpath:application-test.yml"})
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
To my config class but it doesn't work: Spring still load application.yml

I don't think you can tell Spring Boot to ignore application.yml completely. What you can do though is to override all the non desired properties using test specific property files.
Based on the code snippet you posted, any property in application-test.yml will override the equivalent property in application.yml.
Spring Boot considers application-test.yml specific to the profile "test" (which has a higher priority over the default application.yml). No annotation #TestPropertySource is needed.
But if you want to choose another name for your properties file, then you can use #TestProertySource, since files indicated in #TestProperySource parameters have higher priority over the others.
You might want to have a look at Spring Boot external configuration rules for resolving properties

I've end up using #SpringBootTest instead of #DataMongoTest
#SpringBootConfiguration
#ComponentScan(basePackages = {"com.package.services"})
#EnableMongoRepositories(basePackages = {"com.package.repositories"})
public class MongoTestConfig {
private static final MongodStarter starter = MongodStarter.getDefaultInstance();
#Bean
public MongoClient mongoClient() throws IOException {
MongodExecutable _mongodExe;
MongodProcess _mongod;
_mongodExe = starter.prepare(new MongodConfigBuilder()
.version(Version.Main.V3_2)
.net(new Net("localhost", 12345, Network.localhostIsIPv6()))
.build());
_mongod = _mongodExe.start();
MongoClient _mongo = new MongoClient("localhost", 12345);
return _mongo;
}
#Bean
public MongoDbFactory mongoDbFactory() throws IOException{
return new SimpleMongoDbFactory(mongoClient() , "test");
}
#Bean
public MongoTemplate mongoTemplate() throws IOException {
return new MongoTemplate(mongoDbFactory());
}
And my test class is:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyRepositoryTest {
...

Related

Spring Boot Test : Property source with #Value not resolved

I've a problem in my JUNIT test with Spring boot : the #Value is not resolved.
Here the code :
Spring boot config class :
#Configuration
#PropertySource(value="classpath:/config/parametrage-environnement.properties",name="env")
public class ExternalRessourceConfiguration {
//To resolve ${} in #Value
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Class test :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class ConnexionEbicsResourceIntTest {
#Test
#Transactional
public void createConnexionEbics() throws Exception {
restConnexionEbicsMockMvc.perform(post("/api/connexionEbicss")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(connexionEbicsDTO)))
.andExpect(status().isCreated());
Java ressource :
#RestController
#RequestMapping("/api")
public class ConnexionEbicsResource {
#Value("${env['connexion.proxy.host']}")
//#Value("${connexion.proxy.host}")
public String protocol;
#RequestMapping(value = "/connexionEbicss",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<ConnexionEbicsDTO> createConnexionEbics( #RequestBody ConnexionEbicsDTO connexionEbicsDTO) throws URISyntaxException {
log.debug("REST request to save ConnexionEbics : {}", connexionEbicsDTO);
String a = protocol;
}
In java ressource, when I run the test, "a" is null. The #Value was not resolved, why ? My spring boot configuration was ALL bootstraped.
The parametrage-environnement.properties file is located in both paths : src/main/resources/config and src/test/resources/config (copy/paste)
1) Since my controller is mocked, I can't use spring injection directly present in the controller (mocking annihilate Spring !)
2) Syntax
#Value("${env['connexion.proxy.host']}")
is wrong because, env is supposed to be a spring bean (#Bean). See here
So, With #PropertySource, we have to use #Value("${connexion.proxy.host}") syntax and don't forget the Resolver:
//To resolve ${} in #Value
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
return new PropertySourcesPlaceholderConfigurer();
}
3) To set the protocol in the controller class, I need to inject it from the Test class :
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
ConnexionEbicsResource connexionEbicsResource = new ConnexionEbicsResource();
ReflectionTestUtils.setField(connexionEbicsResource, "connexionEbicsService", connexionEbicsService);
**ReflectionTestUtils.setField(connexionEbicsResource, "protocol", protocol);**
ReflectionTestUtils.setField(connexionEbicsResource, "connexionEbicsMapper", connexionEbicsMapper);
this.restConnexionEbicsMockMvc = MockMvcBuilders.standaloneSetup(connexionEbicsResource)
.setCustomArgumentResolvers(pageableArgumentResolver)
.setMessageConverters(jacksonMessageConverter).build();
}
Having the loaded resource bundle in the test class :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
#PropertySource(value="classpath:/config/parametrage-environnement.properties",name="env")
//#PropertySource("classpath:/config/parametrage-environnement.properties")
public class ConnexionEbicsResourceIntTest {
....
#Value("${connexion.proxy.host}")
public String protocol;
Thanks anyway

#TestPropertySource is not loading properties

I'm writing integration test for my spring boot application but when I try to override some properties using #TestPropertySource, it's loading the property file defined in the context xml but it's not overriding the properties defined in the annotation.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {DefaultApp.class, MessageITCase.Config.class})
#WebAppConfiguration
#TestPropertySource(properties = {"spring.profiles.active=hornetq", "test.url=http://www.test.com/",
"test.api.key=343krqmekrfdaskfnajk"})
public class MessageITCase {
#Value("${test.url}")
private String testUrl;
#Value("${test.api.key}")
private String testApiKey;
#Test
public void testUrl() throws Exception {
System.out.println("Loaded test url:" + testUrl);
}
#Configuration
#ImportResource("classpath:/META-INF/spring/test-context.xml")
public static class Config {
}
}
I tested this feature with Spring Boot 1.4
Line below works pretty well
#TestPropertySource(properties = { "key=value", "eureka.client.enabled=false" })
Nevertheless new #SpringBootTest annotation is working as well
#RunWith(SpringRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "key=value", "eureka.client.enabled=false" }
)
public class NewBootTest {
#Value("${key}")
public String key;
#Test
public void test() {
System.out.println("great " + key);
}
}
I had a similar problem. I fixed it by updating the Spring Context beans.xml to use
org.springframework.context.support.PropertySourcesPlaceholderConfigurer instead of org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.
From the JavaDoc of PropertyPlaceholderConfigurer
Deprecated.
as of 5.2; use org.springframework.context.support.PropertySourcesPlaceholderConfigurer instead which is more flexible through taking advantage of the Environment and PropertySource mechanisms.

Spring session with redis - how to mock it in integration tests?

So, Im using spring session in my project.
How to write integration tests in project using it? Should I mock something for spring session internals? Or any reasonable way to use embedded redis?
I saw there was some #EnableEmbeddedRedis annotation in past, but seems it was removed: https://github.com/spring-projects/spring-session/issues/248
//edit
Ive tried to pass MockHttpSession to
mockMvc.perform(post("/register").session(mockHttpSession)
but spring tries and fails to connect to redis anyway.
You can create your own connectionfactory and the redisserializer. Then spring boot won't create their default beans.
Example:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class ApplicationTest
{
#Test
public void contextLoads()
{
}
#EnableRedisHttpSession
#Configuration
static class Config
{
#Bean
#SuppressWarnings("unchecked")
public RedisSerializer<Object> defaultRedisSerializer()
{
return Mockito.mock(RedisSerializer.class);
}
#Bean
public RedisConnectionFactory connectionFactory()
{
RedisConnectionFactory factory = Mockito.mock(RedisConnectionFactory.class);
RedisConnection connection = Mockito.mock(RedisConnection.class);
Mockito.when(factory.getConnection()).thenReturn(connection);
return factory;
}
}
}
I would not suggest to use mockHttpSession, as it will bypass the integration with spring-session library in the tests. I would
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class ExampleControllerV2SpringSessionTest {
#Autowired
private WebApplicationContext wac;
#Autowired
private SessionRepository sessionRepository;
#Autowired
private SessionRepositoryFilter sessionRepositoryFilter;
//this is needed to test spring-session specific features
private MockMvc mockMvcWithSpringSession;
#Before
public void setup() throws URISyntaxException {
this.mockMvcWithSpringSession = MockMvcBuilders
.webAppContextSetup(wac)
.addFilter(sessionRepositoryFilter)
.build();
}
}
Knowing that it's hard to always have redis instance ready during the test, I would suggest you to use this property spring.session.store-type=hash_map for your test cases.
ok, ive just disabled redis by using profiles in my integration tests
#ActiveProfiles("integrationtests")
class RegisterControllerTest extends Specification {...
and extracting #EnableRedisHttpSession to its own class:
#Configuration
#EnableRedisHttpSession
#Profile("!integrationtests")
public class RedisConfig {
}
Its more like workaround than solution, but I dont need to test anything inside session anyway.
This work:
In your HttpSessionConfig define profiles where the configuration is active:
#EnableRedisHttpSession
#Profile("prod")
class HttpSessionConfig {
}
In application-prod.properties add:
#REDIS SERVER
spring.redis.host=xxxxxxxx
And then in your application.properties of test add:
#REDIS SERVER
spring.data.redis.repositories.enabled=false
spring.session.store-type=none

Define spring property values in Java

I have some spring beans which wire in property values using the #Value annotation.
e.g.
#Value("${my.property}")
private String myField;
Usually the values are sourced from property files.
The test I am currently writing uses a fully annotation based configuration.
e.g.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
public class AcceptanceTest implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Configuration
#ComponentScan(basePackages = {
"my.package.one",
"my.package.two"
})
static class ContextConfiguration {
#Bean
public MyBean getMyBean(){
return new MyBean();
}
}
#Autowired
private AnotherBean anotherBean;
#Test
public void testTest(){
assertNotNull(anotherBean);
. . .
}
. . .
I don't wish to reference an external properties file, as I want to keep everything local to the test.
Is there anyway I can specify in java, values for such properties, so that they will be wired in automatically to any beans which need them.
Any help would be appreciated.
Here's one simple approach:
#Configuration
public class PropertiesConfig {
#Bean
public PropertyPlaceholderConfigurer myConfigurer() {
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
Properties props = new Properties();
Map myMap = new HashMap<String, String>();
myMap.put("my.property", "my value");
myMap.put("second.my.property", "another value");
props.putAll(myMap);
configurer.setProperties(props);
return configurer;
}
}
As of Spring Framework 4.1, you can use the #TestPropertySource annotation to declare inlined properties for the ApplicationContext loaded for your tests like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#TestPropertySource(properties = { "foo = bar", "magicNumber: 42" })
public class ExampleTests { /* ... */ }
Consult the Context configuration with test property sources section of the reference manual for details.
Prior to Spring Framework 4.1, the easiest way is to configure a custom PropertySource and register it with the Spring TestContext Framework (before the ApplicationContext is loaded for your test).
You can achieve this by implementing a custom ApplicationContextInitializer and using an org.springframework.mock.env.MockPropertySource like this:
public class PropertySourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getEnvironment().getPropertySources().addFirst(
new MockPropertySource().withProperty("foo", "bar"));
}
}
You can then register your initializer for your test like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(initializers = PropertySourceInitializer.class)
public class ExampleTests { /* ... */ }
Regards,
Sam (author of the Spring TestContext Framework)
If you are using Spock you can also use #TestPropertySource:
#SpringBootTest
#TestPropertySource(properties = [ "my.test.property = bar", "..." ])
It requires the String array to be in Groovy syntax of course, caught me out. I'm using Spock 1.1

Inject test beans into main method

I'm using JavaConfig to manage and wire Spring beans into my Java app. The Java application is a main method - and basically runs as a batch job, invoked via a bash file. Is there a way that I can use a different (test) config in my main method?
public static void main(String[] args) {
final ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
// do Stuff
}
I have used the following annotations successfully before in my test classes:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { TestConfig.class })
, but this does not work for "main" applications. Short of passing in the Spring context to use as an argument, not sure what I can do here. Thanks
You should be able to use profiles in your actual config class to do what you want as well.
By setting the desired Profile you can "inject" the different beans you want.
Your ApplicationConfig might look like:
#Configuration
#Import({
JndiDataConfig.class,
TestDataConfig.class,
)
public class ApplicationConfig {
...
where TestDataConfig looks (in part) like:
#Configuration
#Profile("test")
public class TestDataConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
and where JndiDataConfig looks like:
#Configuration
#Profile("production")
public class JndiDataConfig {
#Bean
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}

Resources