Use embedded database for test in spring boot - java

I have a spring boot application, it has a couple of #Entity classes and #RepositoryRestResource repositort interfaces for them. Now I want to write some tests, where I can check that I can add a new record into my database using those repositories, but I don't want to use my configured MySQL database for it, but instead I want to use some embedded db like H2. At the moment I have an application.properties file, which looks like this:
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=qwerty123
Question: How do I configure my app to use other db for tests? I have no xml in my project, everything is based on annotations. I tried to define #Configuration class with #Bean to create DataSource and then use it with #ContextConfiguration annotation on test class, but it says that it can't load context.

If you are using a Maven project, you can add a application.properties file into your src/test/resources, for example with the following content.
# Create DDL
spring.jpa.hibernate.ddl-auto=create
# H2 in local file system allowing other simultaneous connections
spring.datasource.url=jdbc:h2:~/test;AUTO_SERVER=TRUE
Also, you need to include H2 as dependency (pom.xml):
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.193</version>
</dependency>

Spring Boot provides 2 magic annotations related to JPA autoconfigs for tests: #DataJpaTest and #AutoConfigureTestDatabase.
The javadoc says:
By default, tests annotated with #DataJpaTest will use an embedded
in-memory database (replacing any explicit or usually auto-configured
DataSource). The #AutoConfigureTestDatabase annotation can be used to
override these settings.
If you are looking to load your full application configuration, but
use an embedded database, you should consider #SpringBootTest combined
with #AutoConfigureTestDatabase rather than this annotation.
So, the only thing you absolutely need is a dependency in your pom file:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
That's it. However, spring boot spec also has 2 useful caveats:
You need not provide any connection URLs. You need only include a
build dependency to the embedded database that you want to use.
If you are using this feature in your tests, you may notice that the
same database is reused by your whole test suite regardless of the
number of application contexts that you use. If you want to make sure
that each context has a separate embedded database, you should set
spring.datasource.generate-unique-name to true.
And another one:
If, for whatever reason, you do configure the connection URL for an
embedded database, take care to ensure that the database’s automatic
shutdown is disabled. If you use H2, you should use
DB_CLOSE_ON_EXIT=FALSE to do so. If you use HSQLDB, you should ensure
that shutdown=true is not used. Disabling the database’s automatic
shutdown lets Spring Boot control when the database is closed, thereby
ensuring that it happens once access to the database is no longer
needed.
That's almost all you need to know about Spring Boot and embedded DBs. I see absolutely no reason to use the scope of dependency other than test, unless you actually intentionally configure an embedded DB for your application runtime. Believe it or not H2 jar alone takes 1.8M inside your fat jar. In the world on granular microservices, serverless and lambda functions it does matter what you put inside your apps.
I would also recommend checking the options in #AutoConfigureTestDatabase. I use it with #SpringBootTest, but it can also be used with some other annotations, namely #DataJpaTest, both mentioned above:

You will need to use Spring Profiles - https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html#howto-set-active-spring-profiles
You will define an active profile using "spring.profiles.active = development" and then including H2 in your development profile.
The examples use YAML, but they work in standard properties files as well.

Related

H2 in-memory table doesnt get populated in Spring Boot app [duplicate]

While I was using Spring Boot 1.5, on application startup Hibernate executed schema.sql file located in /resources folder when appropriate configuration is set. After Spring Boot 2.0 release this feature does not work any more. I couldn't find anything about this change in documentation.
Here is my application.properties file content:
spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
#spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
Is there some change in Spring Boot 2.0 or is this an bug/issue?
Check the documents here.
In a JPA-based app, you can choose to let Hibernate create the schema
or use schema.sql, but you cannot do both. Make sure to disable
spring.jpa.hibernate.ddl-auto if you use schema.sql.
You have spring.jpa.hibernate.ddl-auto=create-drop that's why schema.sql is not executed.
Looks like this is the way Spring Boot works.
Edit
I think that the problem(not really a problem) is that your application points to a mysql instance.
See the current Spring Boot properties:
spring.datasource.initialization-mode=embedded # Initialize the datasource with available DDL and DML scripts.
The default value is embedded - e.g. initialize only if you're running and embedded database, like H2.
Also see the answer of Stephan here. He said:
Adding spring.datasource.initialization-mode=always to your project is
enough.
So try to set:
spring.datasource.initialization-mode=always
Not embedded (e.g. MySQL)
If you load a database that is not embedded, in Spring Boot 2 you need to add:
spring.datasource.initialization-mode=always
Check the Migration Guide:
Database Initialization
Basic DataSource initialization is now only enabled for embedded data
sources and will switch off as soon as you’re using a production
database. The new spring.datasource.initialization-mode (replacing
spring.datasource.initialize) offers more control.
Embedded (e.g. h2)
I once had a similar problem, even though it was an h2 (so it was an embedded DB), my h2 configuration was activated by a my-test profile.
My test class was like:
#RunWith(SpringRunner.class)
#SpringBootTest // does not work alone
#ActiveProfiles("my-test")
public class MyEntityRepositoryTest {
The problem is #SpringBootTest alone did not initialize the test database. I had to either use #DataJpaTest or #SpringBootTest+#AutoConfigureTestDatabase. Examples
#RunWith(SpringRunner.class)
#DataJpaTest // works
#ActiveProfiles("sep-test")
public class MyEntityRepositoryTest {
or
#RunWith(SpringRunner.class)
#SpringBootTest // these two
#AutoConfigureTestDatabase // together work
#ActiveProfiles("sep-test")
public class MyEntityRepositoryTest {
Recent Update
As of Spring Boot Version 2.7
the property spring.datasource.initialization-mode has been removed.
You should from this version and onwards use the replacement property spring.sql.init.mode
Example: spring.sql.init.mode:always
Spring Boot 2.7 changelog
It works fine for me, you can try it. Set datasource type to what you like instead of HikariCP.
spring.datasource.initialization-mode=always
spring.datasource.type=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
spring.jpa.hibernate.ddl-auto=none
There have another problem may result data.sql can not be executed,when you don't config the spring.jpa.hibernate.ddl-auto=none,that the data.sql will not be execute d.
I was able to make application run only after excluding Hikary CP like that:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</exclusion>
</exclusions>
</dependency>
Please, see the issue here

Why does the addition of a dependency in Maven trigger functionality?

I have a simple question: I'm just getting started with Open API 3. For this purpose I have added the following dependency in Maven.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.2.30</version>
</dependency>
With the addition of this dependency, can I access the service via localhost:8082/v3/api-docs without having previously set anything and called a function of the dependency? How can this happen? What is the concept behind this ?
Adding the OpenAPI dependency in your Maven pom.xml just adds the librar(ies) to your project. That's all.
If this were a "traditional" project (like a JSP web app, for example), you'd have to write the code to create the web service (e.g. "localhost:8082/v3/api-docs").
But it sounds like your project might be Spring Boot:
https://developer.ibm.com/technologies/java/tutorials/j-spring-boot-basics-perry/
If you let it, Spring Boot will use its #EnableAutoConfiguration
annotation to automatically configure your application.
Auto-configuration is based on the JARS in your classpath and how
you’ve defined your beans:
Spring Boot uses the JARs you have specified to be present in the CLASSPATH to form an opinion about how to configure certain automatic
behavior. For example, if you have the H2 database JAR in your
classpath and have configured no other DataSource beans, then your
application will be automatically configured with an in-memory
database.
Spring Boot uses the way you define beans to determine how to automatically configure itself. For example, if you annotate your JPA
beans with #Entity, then Spring Boot will automatically configure JPA
such that you do not need a persistence.xml file.
It is called convention over configuration.
Wiki link https://en.wikipedia.org/wiki/Convention_over_configuration

Does Liquibase runs before registering all the beans in spring boot application?

I have integrated Liquibase with my spring Boot application. The one confusion which I have is that - does Liquibase run before registering all the beans. If we want to fetch some property from the DB in the bean declaration method and that property is written by the sql script which will be executed by Liquibase. So, which of the two things will happen first?
I do know that liquibase automatically gets integrated to the startup of the spring boot application i.e, it runs everytime, the application runs. But, does it get loaded before loading other beans of the same application?
My liquibase dependency :
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>3.8.2</version>
</dependency>
So, which of the two things will happen first?
Liquibase runs it's scripts.
Spring-Boot initializes your beans.
So you should be able to get data (which Liquibase has just inserted) from database during bean initialization.
But as was suggested in the comments, you should try it yourself and add logs to your bean initialization methods. This will give you a way better understanding of Spring-Boot applications start-up process.

Only overriding values with src/test/resources/application.properties for Integration test

I have an integration test that spins up a running copy of my Spring Boot rest api and performs tests with rest template. Currently I can use src/test/resources/application.properties to specify/override any properties I want to set for testing. The problem is that this doesn't only act as overriding, I have to duplicate all of the properties in src/main/resources/application.properties as well. Ideally I would like it to read both files and use the test properties to override any properties found in both files. This works for profile specific properties such as when using both src/main/resources/application.properties and src/main/resources/application-dev.properties, but doesn't seem to be the case for running tests. I know I can use a custom named properties file and pull that in with an annotation but I'd like to avoid that route to keep things clean.
I'm using Spring Boot 2.1.0.RELEASE

reading and writing configuration in Spring Boot

I'm building a fairly simple Spring Boot application which needs some configuration to be set (and regularly updated as part of it's use). I'd like to create a simple admin interface and first-run wizard to set/update this configuration.
I'd like a way to easily read and write these configuration values within the application and have them persist. I would like to avoid the overhead of a database for 5-10 configuration strings. There is some good documentation on externalising configuration in Spring Boot but it doesn't talk about how this config could be updated and persisted by the app.
Options I have come up with:
There is a write option with Spring configuration that I'm not aware of (this would be awesome)
Don't use the Spring Boot configuration functionality, instead use apache commons configuration (or similar??) to read and write to a file which lives in a location specified by an environment variable
as per option 2 but use HSQL, H2 or Derby as a file-based database
Thanks for any suggestions as to how best to achieve this.

Categories

Resources