Spring boot application not using the DB driver defined in application-test.properties - spring-boot

I decided I would like to add a h2 DB to my spring boot application for testing purposes. I added a new application-test.properties to my folder test/resources with all the necessary configuration. The problem is that when I run the tests, I always get the connection to the mysql database.
I can see the application-test.properties is being used because the loggin.level changes from DEBUG to ERROR in my tests.
For my MySql DB I have a file which provides the datasource
Code
application-test.properties file
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username = sa
spring.datasource.password =
spring.datasource.driver-class-name = org.h2.Driver
spring.h2.console.enabled=false
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.springframework.security=ERROR
application.properties file
mysql.database.host=localhost
mysql.database.port=3306
mysql.database.db=mydb
mysql.database.user=root
mysql.database.password=root
mysql.database.driver=mysql
logging.level.org.springframework.security=DEBUG
datasource class
#Bean
open fun getDataSource(): DataSource? {
val dataSourceBuilder = DataSourceBuilder.create()
dataSourceBuilder.url("jdbc:$driver://$databaseHost:$databasePort/$databaseName")
dataSourceBuilder.username(databaseUser)
dataSourceBuilder.password(databasePassword)
return dataSourceBuilder.build()
}
test
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("test")
class AdAccountControllerTest {
#Autowired
lateinit var mockMvc: MockMvc
#Test
fun `we should get unauthorized status when we dont provide credentials`() {
mockMvc.perform(get("/api/v1/ad-account"))
.andExpect(status().isOk)
.andDo(print())
}
}

Related

SpringBoot MockMVC Controller Test with in-memory H2 not creating JPA entities as table or not inserting seed data

Status returns 200 but when i checked the logs cannot see any H2 logs for creating tables or inserting data. So, what do you suggest me to do.
Another thing I want to mention is that while testing the Repository, I was able to do my Repository tests with h2 using the #DataJpaTest annotation. Below you can see my sample properties file and controllertest file.
#RunWith(SpringRunner.class)
#WebMvcTest(VehicleController.class)
#ContextConfiguration(classes=DemoApplication.class)
#AutoConfigureMockMvc
public class VehicleControllerTest {
#Autowired
private WebApplicationContext context;
#Autowired
private MockMvc mvc;
#MockBean
private VehicleService vehicleService;
#Before
public void setup() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void RetrieveAllVehicles() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/api/vehicle").content("application/json");
MvcResult result = this.mvc.perform(requestBuilder).andExpect(status().isOk())
.andReturn();
assertEquals(12 , 12);
}
Application Properties file like that for in memory database with H2.
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.show-sql=true
spring.datasource.initialization-mode=always

Spring and Flyway - migrate before application context starts up

As the title suggests, I am looking for any means that could help me run Flyway migrations before Springs application context (persistence context to be precise) is loaded. The reason for that is I have few queries that run at the startup of the application. This leads to my tests failing as queries are being executed on database tables that do not yet exist. I am using H2 as my test database. Right now I am using only flyway core dependency:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>6.5.0</version>
<scope>test</scope>
</dependency>
and I have a single Flyway configuration class as follows:
#Configuration
class FlywayConfig {
private static final String resourcePath = "classpath:flyway/migrations";
private static final String sampleDataPath = "classpath:flyway/sample_data";
#Bean
Flyway flyway(#Value("${spring.datasource.url}") String dataSource,
#Value("${spring.datasource.username}") String username,
#Value("${spring.datasource.password}") String password) {
FluentConfiguration fluentConfiguration = Flyway.configure().dataSource(dataSource, username, password);
fluentConfiguration.locations(resourcePath, sampleDataPath);
Flyway flyway = fluentConfiguration.load();
return flyway;
}
}
and the properties are defined in application.yml
spring:
datasource:
username: sa
password: sa
url: 'jdbc:h2:mem:testdb;Mode=Oracle;IGNORE_CATALOGS=TRUE;DB_CLOSE_DELAY=-1;'
platform: h2
h2:
console:
enabled: true
jpa:
show-sql: true
What I would like to achieve is that: 1. flyway does migration 2. Spring context loads up (in that particular order)
I managed to be able to acomplish what I wanted by creating DataSource object manually in configuration file (not by Spring automatically from application.yml) and using #DependsOn on the DataSource object. This way I made sure that any possible database connection from the application context would be established once I do the migration in the Flyway bean (which btw I also tweaked). I was cleaning and migrating Flyway right before tests and now I have to do this while initalizing application context beans. Here is the code which worked for me:
#Configuration
class DatabaseConfig {
private static final String resourcePath = "classpath:flyway/migrations";
private static final String sampleDataPath = "classpath:flyway/sample_data";
private static final String dataSourceUrl = "jdbc:h2:mem:testdb;Mode=Oracle;IGNORE_CATALOGS=TRUE;DB_CLOSE_DELAY=-1;";
private static final String username = "sa";
private static final String password = "sa";
#Bean("flyway")
public Flyway flyway() {
FluentConfiguration fluentConfiguration = Flyway.configure().dataSource(dataSourceUrl, username, password);
fluentConfiguration.locations(resourcePath, sampleDataPath);
Flyway flyway = fluentConfiguration.load();
flyway.clean();
flyway.migrate();
return flyway;
}
#DependsOn("flyway")
#Bean
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName("org.h2.Driver");
dataSourceBuilder.url(dataSourceUrl);
dataSourceBuilder.username(username);
dataSourceBuilder.password(password);
return dataSourceBuilder.build();
}
}
and here is the application.yml file (I got rid of datasource related records):
spring:
h2:
console:
enabled: true
jpa:
show-sql: true
flyway:
enabled: false

Springboot 2.0 JUnit test #Tranactional rollback doesn't works

I migrated some projects from Springboot 1.5.10 to 2.0.
Springboot 2.0.3Release, JDK10, mysql, hikari-cp
After this work, in JUnit test, all data in test cases remains at database. I think it doesn't works #Tranactional - org.springframework.transaction.annotation.Transactional
Here is part of application.yml and test class.
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
jpa:
show-sql: true
hibernate:
ddl-auto: none
database: mysql
database-platform: org.hibernate.dialect.MySQL5Dialect
Here is datasource.
#Configuration
#EnableTransactionManagement
public class DatasourceJPAConfig {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
}
Here is part of JUnit test class.
#Transactional
#Rollback(true)
#RunWith(SpringRunner.class)
#ActiveProfiles("local")
#SpringBootTest
public class RepoTests {
#Autowired
private TestRepository testRepository;
#Test
public void saveTest() {
var name = "test";
var description = "test description"
var item = TestDomain.builder()
.name(name)
.description(description)
.build();
testRepository.save(item);
var optional = testRepository.findById(item.getId());
assertTrue(optional.isPresent());
assertEquals(optional.get().getDescription(), description);
assertEquals(optional.get().getName(), name);
}
}
after to run saveTest method, increase 1 row at database.
Add datasource to test and set auto commit to false
#Autowired
private DataSource dataSource;
And inside test
((HikariDataSource)dataSource).setAutoCommit(false);

Disable production datasource autoconfiguration in a Spring DataJpaTest

In my application.yml, I have the following configuration (to be able to customize variable on different environment with docker/docker-compose) :
spring:
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
The trouble is that Spring tries to autoconfigure this datasource while I am in #DataJpaTest, so with an embedded H2 database, and obviously it does not like placeholders....
I tried to exclude some autoconfiguration :
#DataJpaTest(excludeAutoConfiguration =
{DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
But then, nothing works, entityManagerFactory is missing, ...
I could probably use profiles but if possible I preferred another solution.
Did you try defining your own Datasource bean?
#Import(JpaTestConfiguration.class)
#DataJpaTest
#Configuration
public class JpaTestConfiguration{
//...
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
//...
}

Configure h2 for spring boot

I'm trying to configure spring boot to set my test datasource to use h2 in postgresql mode.
I set these lines in my test/resources/application:
spring.datasource.url=jdbc:h2:mem:db1;MODE=PostgreSQL
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
But spring boot keep loading me default h2 configuration.
How can I force spring boot to use my special h2 configuration ?
just do it in java-configuration like this:
#Configuration
#EnableAutoConfiguration
#Profile({ "dev", "demo" })
public class EmbeddedDatabaseConfiguration {
#Bean(name = "dataSource")
public DriverManagerDataSource getDataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("org.h2.Driver");
driverManagerDataSource.setUrl("jdbc:h2:mem:mylivedata;IGNORECASE=TRUE;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1");
return driverManagerDataSource;
}
}

Resources