Spring4 JUnit tests : Load SQL to a H2 db - java

I'm trying to write tests for a Spring Boot (Spring 4) Application.
My Junit test class is configured like this to allow autowired.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = SpringApp.class)
public class MyServiceTest {
...
My src/main/resources/application.properties is like this
spring.jpa.database=POSTGRESQL
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=update
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost/mydb
spring.datasource.username=BNF0016779
spring.datasource.password=
In test context, src/test/resources/application.properties is just empty.
In can query the db as usual, creating objects...
But I'd like to create a data init sql.
To begin with a strange behavior, It seems that Spring loads any "schema.sql" in classpath.
Something like the following is not required ?
//This is not required to execute schema.sql
#Configuration
public class DatabaseTestConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.build();
}
}
Then, I can't create any Table from this SQL.
Always receive org.h2.jdbc.JdbcSQLException: Table "MY_TABLE" already exists; SQL statement:
H2 is supposed to be a in-memory DB, no keeping data between two startup !
Why do I receive these errors ?
Any ideas ?
Thanks

Spring Boot will in fact execute a file named schema.sql in the root of the classpath by default. Furthermore, Spring Boot will also automatically create an embedded database for your application unless you instruct it otherwise. Consult the "Initialize a database using Spring JDBC" section of the Spring Boot reference manual for details.
H2 is supposed to be a in-memory DB, no keeping data between two
startup !
Yes and no.
If Spring Boot creates an embedded H2 database for you, yes it will be in-memory.
However, the database is actually a bean in the ApplicationContext (just like any other Spring-managed component). Thus it lives as long as the ApplicationContext lives, and the Spring TestContext Framework caches contexts between tests: that's one of its main features. In other words, the embedded database will not be recreated between tests (unless you annotate your test classes or test methods with #DirtiesContext). Consult the Context caching section of the Spring Framework reference manual for details.
Regards,
Sam (author of the Spring TestContext Framework)

H2 can be in memory. But I'm assuming the default DataSource it uses is not.
You can set the DataSourceFactory on the EmbeddedDatabaseBuilder to generate a DataSource that connects with a url such as jdbc:h2:mem:test.

Related

Hibernate/Spring framework: path of the database in a configuration file

I am trying to write a simple Hibernate application and I want the SQLite database location to be changed according to an application configuration file.
What I was trying to do was therefore retrieving the path of the database from a text file in the project and putting it inside dbLocation, then running the following piece of code:
Configuration config = new Configuration();
config.setProperty("hibernate.connection.url", "jdbc:sqlite:" + dbLocation);
Is there a better and more "standard" way to do so? I'm using Spring Boot for my application and I just realized there's afile called application.properties. May I use this one maybe? I'm pretty new to both Hibernate and the Spring framework.
In Spring Boot application properties you can externalize your application properties so they are configured/managed outside your application source code.
Once a property is defined in application.properties you can use SpringBoot built-in feature to access the values
#Configuration
public class ApplicationProperty {
#Value("${prop}")
private String prop;
With Spring Boot another way is to use #ConfigurationProperties.
Example from the documentation can be found here
A comparison between #ConfigurationProperties and #Value annotation from the documentation
Feature #ConfigurationProperties #Value
Relaxed binding Yes No
Meta-data support Yes No
SpEL evaluation No Yes

Connecting to HSQLDB

I'm developing a Spring Boot application using an embedded HSQLDB for local deployment. I defined the bean as follows
#Bean
public DataSource ds() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:db/schema.sql")
.addScript("classpath:db/data.sql")
.build();
}
However, when I try to fetch all the entities from the database with JPA, I get an empty result.
I would like to execute query against the embedded database at runtime to see the actual data. What port/protocol the HSQLDB listens to, and what client I need to connect and execute query?
The solution was to add following properties to application.properties
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=validate
This is because the default strategy for hibernate is to drop and re-create the the database schema for the entities it manages, which negated my database scripts.

Executing Spring Boot Integration tests on existing mysql database

I am using spring boot 2 and I am trying to execute integration tests on repositories by creating tests with annotations:
#RunWith(SpringRunner.class)
#DataJpaTest
public class SomeTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private SomeRepository repository;
// CONTENT
}
I have liquibase migrations and I want those tests to be run on special mysql database. However spring boot by default is trying to configure embeded h2 database. And after removing h2 dependencies from POM file I have got:
Failed to replace DataSource with an embedded database for tests. If you want an embedded database please put a supported one on the classpath or tune the replace attribute of #AutoconfigureTestDatabase
When I run my application it runs perfectly fine, since I have filled application.yml with proper database connections. However when I add application.yml to test resources nothing happens.
Can anyone tell me how to configure those tests properly to use mysql database?

Configuring in-memory or embedded database to test production code

I have a requirement where in I have to test a DAO java class in production code using an in-memory database. The DAO performs insert operation using a different connection configuration.
I tried configuring hsql embedded database which comes with spring but looks like it needs programmatic configuration setup within the DAO production code for it to work but I cannot change the production code. Can someone suggest me a way to configure a embedded database to test my production DAO code through junits.
I tried this configuration:
#Before
public void setUp()
{
db = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript("create-table.sql").addScript("insert-data.sql").build();
}
But this above code is in my junit. Without this above code I am not seeing a way to configure the in-memory database. I cannot have this code in my production environment. How can I configure the in-memory database without making changes to the production code.
I created a TestConfig as my spring configuration file for my junits, and configured two beans in there:
EmbeddedDatabase bean to return the embedded database.
#Bean
#Profile("test-profile")
public EmbeddedDatabase embeddedDatabase()
{
return new EmbeddedDatabaseBuilder().setName("Derby").setType(EmbeddedDatabaseType.DERBY).addScript("schema.sql").build();
}
Then a bean for getting the Connection out of the above created database.
#Bean
#Profile("test-profile")
public Connection connection() throws SQLException
{
return embeddedDatabase().getConnection();
}
My production code gets the Connection object from spring's ApplicationContext. So I configured my junits to run using my TestConfig so the production code pulled in the embedded database connection object and passed it along. The tests passed.

Spring Boot with datasource when testing

I am using Spring Boot application and the auto cofiguration is enabled. The main Application file is marked as #EnableAutoConfiguration. The datasource is lookedup from JNDI is configured using java config and the class which create the datasource is marked as #Configuration.
I have a test class as below.
#RunWith( SpringJUnit4ClassRunner.class )
#WebAppConfiguration
#ContextConfiguration( classes = Application.class )
public class TestSomeBusiness {}
The issue is when I run the test case, the datasource jndi lookup happens, which fails because the test case is not running inside a server environment. As far as I know the classes in classpath marked with #Configuration are executed and that the reason the datasource lookup is being called.
The work around for now I have found is instead of JNDI lookup create the datasource using DriverManagerDataSource, so that even if its not a server environment the datasource lookup won't fail.
My questions are:
1) How do we generally deal with datasource (when looking up from JNDI) in
spring boot application for testing ?
2) Is there a way to exclude the datasource configuration class from being called when executing test case ?
3) Should I create an embedded server so that the JNDI lookup can be done when executing test case ?
2) Is there a way to exclude the datasource configuration class from being called when executing test case ?
You can add a application.properties config file into your src/test/resources and spring boot would pick those configurations in test environments. I suppose, you have application.properties in your src/main/resources like this:
spring.datasource.jndi-name=some_jndi
This JNDI resource will be used in your production environment. For your test environment you can use a, say MySQL database, by adding these configurations into your test application.properties:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
3) Should I create an embedded server so that the JNDI lookup can be
done when executing test case ?
As i said, you can totally bypass the fact that you're using JNDI for production by adding test specific configurations.
1) How do we generally deal with datasource (when looking up from
JNDI) in spring boot application for testing ?
You can mock JNDI resources using facilities available in org.springframework.mock.jndi package. For example by using SimpleNamingContextBuilder you can:
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("jndi_name", dataSource);
builder.activate();
The other option is, of course, using Non JNDI resources in test environments.

Categories

Resources