I'm developing an app in Spring Boot. I use a PostreSQL DB for production, and I want my JUnit 5 tests to run on a H2 memory DB. Problem is, after some configuration, the tests still don't seem to run on the in-memory db:
I can access entities from the prod db (a saved entity doesn't persist in the prod db tho)
if I grep through the test logs, I can see that Hibernate uses org.hibernate.dialect.PostgreSQLDialect
#DataJpaTest
#SpringBootTest
#TestPropertySource(locations = "classpath:application-test.properties")
#ExtendWith(SpringExtension.class)
#ActiveProfiles("test")
public class ClinicTest {
#Resource
private ClinicRepository clinicRepository;
#Test
public void givenClinic_whenSave_thenGetOk() {
var clinic = new Clinic();
clinic.setName("asd asd");
clinic.setShortName("asd");
// the ids of prod db entities are printed
clinicRepository.findAll().forEach(clinic1 -> System.out.println(clinic1.getId()));
// the id keeps incrementing between runs
System.out.println(clinicRepository.save(clinic).getId());
}
}
application-test.properties
jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:testdb
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create-drop
spring.test.database.replace=none
What should I change to run self-contained test on a H2 in memory database?
Spring, by default, creates an H2 DB for the test. You don't need to specify it in your properties file.
Just add h2 in your pom.xml and set its scope to test. Spring Boot should handle the rest.
Your application-test.proprties does not have user and pasword
try adding this:
#--------------------- DB Connection ------------------
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=
#--------------------JPA-ORM Properties-----------------
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.format_sql=true
Related
I am writing integration tests for a project with multiple datasources and want to test the repository and service layer. Problem is that the #Transactional annotation is not working and data inserted during tests is persisted.
This is a simple IT. I need to use #SpringBootTest instead of #DataJpaTest because multiple datasources are configured in a bean which handles assigning the right datasource to the correct repository.
#SpringBootTest(classes = { MyApp.class, TestSecurityConfiguration.class })
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#ActiveProfiles("database-test")
#Transactional
#Rollback
public class MyIT {
#Autowired
ChannelRepository channelRepository;
#Test
public void testChannels() {
Channel testChannel1 = new Channel();
testChannel1.setDescription("Test Channel 1");
channelRepository.save(testChannel1);
Channel testChannel2 = new Channel();
testChannel2.setDescription("Test Channel 2");
channelRepository.save(testChannel2);
Channel channel = channelRepository.findById(1).get();
assertThat(channel).isNotNull();
}
}
The dialect configured in the application.yml is "org.hibernate.dialect.SQLServer2012Dialect" and the database is our test database that runs on a dedicated server, not an embedded database.
The data is inserted without rollback.
After looking at the JpaTransactionManager logs using:
logging:
level:
sql: DEBUG
ROOT: DEBUG
org.springframework.orm.jpa: DEBUG
org.springframework.transaction: DEBUG
I saw that for each .save() call there was a new inner transaction. I tried to specify the transaction manager manually by passing the value to the #Transactional annotation and now it works. Looks like the DataSource beans are not picked up entirely correct. I got the idea based on this article where a ChainedTransactionManager is used for multiple datasources https://medium.com/preplaced/distributed-transaction-management-for-multiple-databases-with-springboot-jpa-and-hibernate-cde4e1b298e4
I have a Rest controller GET method
#GetMapping("/users")
public List<Users> getAllUsers() {
return userRepo.findAll()
}
I need to test it, but I get the "Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured". The problem is that the nature of production does not allow me to use real connection or change it to embedded one. Is there a way to mock the DB somehow?
The project is almost the same to the one in this article:
https://dzone.com/articles/how-to-create-rest-api-with-spring-boot
Either you can use #MockBean annotation to mock the UserRepository or you can create an embedded in-memory H2 DB for the test by adding following properties in application-test.properties:
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
You can follow this link to understand it in detail.
I need to make tests with embedded database and I want to check results in h2-console. I have configured properties for tests and I want to store my test data to have a look on it, but it always writes Replacing 'dataSource' DataSource bean with embedded version and uses another h2 DB like "jdbc:h2:mem:1f4af8a8-3e14-4755-bcbd-5a59aa31033e". What can I do with this problem?
"application-test.properties":
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./subdirectory/demodb
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
My test class:
#DataJpaTest
#ActiveProfiles("test")
class ProductRepositoryTest {
#Test
void findByProductName() {
//...
}
}
By default, the #DataJpaTest annotation replaces your production DB with an embedded one, wraps every test method in a transaction and rolls it back at the end of the test.
If you want to run your test as if it was a "real" operation on the DB, you can add the following annotations to your test class:
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#Transactional(propagation = Propagation.NOT_SUPPORTED)
The first one tells Spring not to use the embedded DB, while the second one tells it to work non-transactionally (every query will be persisted).
I have a integration test but the problem is, that it uses the datasources from the main application.properties which is a mssql database. In my tests I want to use a h2 database for that I have created a application-test.poperties in src/test/resources . In my test class I defined the #TestPropertySource which links to this property file. But in the log output I can see that the testclass still uses the mssql database connection.
Here is my test class
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Transactional
#TestPropertySource(locations="classpath:application-test.properties")
public class UserControllerTest {
#LocalServerPort
private int port;
TestRestTemplate restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
...
Here is my src/test/resources/application-test.properties file
spring.datasource.datasource.url=jdbc:h2:mem:scserver
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServerDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=create-drop
#logging
logging.level.root=info
logging.file=foo-spring-rest.log
#required for SpringBootTest does not know why
spring.main.allow-bean-definition-overriding=true
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
try to use instead of
#TestPropertySource(locations="classpath:application-test.properties")
this
#TestPropertySource(locations = {"classpath:application-test.properties"})
// dont forget the curvy brackets, because location'S'
or the profile annotation
#ActiveProfiles("test")
I'm trying to setup the database schema and some test data with liquibase for some tests. Each test has a separate changelog which setup the schema and some specific data for the test.
In order to make my tests working, I need to drop the schema before each test and fill it with new test data. However, it seems that this is not working because some tests are failing because the old test data is still available. I think something with my configuration is not correct. How can I force liquibase to drop the schema before each test?
My tests look as following:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyTestConfig.class)
#TestPropertySource(properties = "liquibase.change-log=classpath:changelog/schema-with-testdata.xml")
public class MyRepositoryTest {
The config for the tests looks as follows:
#SpringApplicationConfiguration
#Configuration
#EnableAutoConfiguration
#ComponentScan("com.mypackage")
#EntityScan(basePackages = { "com.mypackage.domain" })
#EnableJpaRepositories(basePackages = { "com.mypackage.domain", "com.mypackage.infra.persistence" })
public class MyTestConfig {
And the application.properties under src/main/test/resources is
liquibase.drop-first=true
spring.jpa.hibernate.ddl-auto=none
There is a spring.liquibase.dropFirst config property. Maybe this is what you're looking for?
Not sure if this completely answers your question. There is another property liquibase.default-schema=schemaNameToCreate
But even with that I was never able to get it to create the schema from scratch.