Initialize database only when running Test using Spring java based configuration - java

I have the code to create data source and run scripts to create schema and add in data using java based spring configuration. I want to run those scripts only in test mode. Is there any annotation that I need to specify on top of the database initializer bean that would do the job?

You can use #profile annotation for this, like:
#Configuration
#Profile("test_profile")
public class StandaloneDataConfig {
#Bean
public DataSource dataSource() {
// do data source creation/initialization
}
}
Then use:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class,
classes={StandaloneDataConfig.class})
#ActiveProfiles("test_profile")
public class TransferServiceTest {
#Autowired
private TransferService transferService;
#Test
public void testTransferService() {
// test the transferService
}
}
You can read this blog post from the Spring team to learn more details.

Related

Is there any way to create a #ConditionalOnMissingBean but only after spring is fully configured?

I'm building a Spring Boot Starter for a college project on Java Reflection and Bytecode alteration.
The Reflection/Bytecode is done now, but it will scan for Spring #Controllers/#RestControllers so it can detect certain annotations to run the process.
My question here is what's the best approach? Seems to me that an annotation processor doesn't quite work nicely, and my idea is to create a #Configuration class. Now I need to ensure that all #Controller beans have been booted before I actually process them and I also need to put the result of this processing in a bean that could already exist.
So for example:
#Configuration
public class TestConfig {
#Autowired //I want to autowire but it may not exist, if the user doesn't define I need to create it
private ExternalAnnotatedRequestsModel model;
#Autowired // needed for the framework to acess spring controllers
private ConfigurableApplicationContext ctx;
#Bean // this can also be overriden since the definitions can be done via yaml
public ExternalRequestsProvider() {
return new AnnotationExternalRequestsProvider(ctx);
}
}
Now I also want that when the ExternalRequestsProvider bean is started, it runs the process method and saves the result in the object in the "model" variable.
Using #EventListener for ApplicationReadyEvent to run your process after Spring is fully configured.
#Configuration
public class ExternalRequestsConfig {
#Autowired
private ExternalAnnotatedRequestsModel model;
#Autowired
private ExternalRequestsProvider provider;
#EventListener(ApplicationReadyEvent.class)
public void onApplicationReady(ApplicationReadyEvent event) {
// do your process
}
}

Spring Boot 1.5.4: exclude configuration class in unit test

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.

Spring Boot Exclude DataSource Configuration

I have a small application that when live, makes a database connection, and stores and persists some data.
I'm currently in the midsts of trying to write some tests, and I'm wanting to completely cut off the database part of the application, and just mock it in the tests.
The Datasource is setup with a configuration class.
#Component
#Configuration
public class DataSourceConfiguration {
#Bean
public DataSource myDataSource() { ... }
}
and a test boostrap that currently looks similar to
#RunWith(SpringRunner.class)
#EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class MyTest {
}
When running the test, I can see that Spring is trying to instantiate Hibernate, and a connection to the db, I assume because of my config class. How can I stop Spring from doing this?
No Need to use : #EnableAutoConfiguration
We can narrow down the tests to just the web layer by using #WebMvcTest as below,
#RunWith(SpringRunner.class)
#WebMvcTest
public class WebLayerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello World")));
}
}
Refer how to test spring application with only web or using complete application context loading : https://spring.io/guides/gs/testing-web/ refer mocking example : http://www.lucassaldanha.com/unit-and-integration-tests-in-spring-boot/

Second datasource in spring application.properties for tests?

I have datasource defined in my application.properties as Oracle database and that's ok, the controller & repository work fine, I can persist entities and fetch database records.
I have integration tests written. Before I connected my app with database I created some objects and persisted them in #PostConstruct method - and that was ok. But now, when I connected everything with database, my tests try to fetch records from the table which is pretty large.
I think that's due to my application.properties file in which defined datasource is Oracle database.
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:#blabla
spring.datasource.username=blabla
spring.datasource.password=blabla
spring.jpa.hibernate.ddl-auto=none
spring.jpa.generate-ddl=false
I want to carry on tests using some in-memory HSQL, not real database. But I still want my controller and repository to use the real one. How can I do it? Is there any possibility to add second datasource in application.properties? Or maybe an easier solution?
In Spring 4 you have #Profile annotation so you can use its advantage.
Create another like application-test.properties file with it's own properties.
Create configuration for your tests:
#Configuration
#Profile("test")
public class TestConfiguration {
....
}
Then annotate your class with #ActiveProfiles annotation:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#ActiveProfiles("test")
public class TestRepository {
...
}
There are many ways to achieve this, one way is to use Spring profiles. The test profile would use a different properties file than the production one.
Spring has org.springframework.mock.jndi.SimpleNamingContextBuilder package that allows you to bind the dataSource programatically.
Sample Test class that I use:
public class MockJNDIContext {
#BeforeClass
public static void setUpClass() throws Exception {
SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();//Use your own Connection Pool DS here as you require
ds.setURL("jdbc:oracle:thin:#10.xxx.xxx.xx:9999:SID");
ds.setUser("USER");
ds.setPassword("PASSWORD");
//Bind it to the JNDI you need
builder.bind("java:comp/env/jdbc/MY/APP", ds);
}
#Test
public void test(){
System.out.println("JNDI Initialized");
}
}
Suite Class:
#RunWith(Suite.class)
#Suite.SuiteClasses({
MockJNDIContext.class,
InitializeTestConfig.class
})
public class ServiceSuite{
}
May be this helps? If you are trying to load from one more application.props, use one more class (InitializeTestConfig.class) that initializes and passes the DS args and add to suite as mentioned above and try?

What to use instead of SimpleJdbcTestUtils?

I am trying to set up a database test using Spring and DBUnit. I have a script to run before each test. The code below works but SimpleJdbcTemplate is deprecated. The method executeSqlScript is being moved to JdbcTestUtil as part of the 3.2 release but we're on 3.1.x. What to use instead?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTestScript{
#Autowired
public DataSource dataSource;
#Autowired
public Resource script;
#Before
public void setup() {
SimpleJdbcTestUtils.executeSqlScript(
new SimpleJdbcTemplate(dataSource), script, true);
}
#Test
public void testInsert() {
}
}
You should just suppress the warning and go on. Once you switch to Spring 3.2, the transition will be trivial (remove all the Simple prefixes). There is no real reason to avoid SimpleJdbcTemplate at all costs in these tests, as its whole functionality is in JdbcTemplate under the same name.

Categories