Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to re-create database before each test in Spring?

My Spring-Boot-Mvc-Web application has the following database configuration in application.properties file:

spring.datasource.url=jdbc:h2:tcp://localhost/~/pdk spring.datasource.username=sa spring.datasource.password= spring.datasource.driver-class-name=org.h2.Driver 

this is the only config I made. No any other configurations made by me anywhere. Nevertheless the Spring and subsystems are automatically recreate database on each web application run. Database is recreated namely on system run while it contains data after application ends.

I was not understanding this defaults and was expecting this is suitable for tests.

But when I started to run tests I found that database is recreated only once. Since tests are executed at no predefined order, this is senseless at all.

So, the question is: how to make any sense? I.e. how to make database recreate before each test as it happens at application first start?

My test class header is follows:

@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = myapp.class) //@WebAppConfiguration @WebIntegrationTest @DirtiesContext public class WebControllersTest { 

As you see, I tried @DirtiesContext at class level and it didn't help.

UPDATE

I have a bean

@Service public class DatabaseService implements InitializingBean { 

which has a method

@Override     @Transactional()     public void afterPropertiesSet() throws Exception {         log.info("Bootstrapping data...");         User user = createRootUser();         if(populateDemo) {             populateDemos();         }         log.info("...Bootstrapping completed");     } 

Now I made it's populateDemos() method to clear all data from database. Unfortunately, it does not called before each test despite @DirtiesContext. Why?

like image 598
Dims Avatar asked Jan 05 '16 16:01

Dims


People also ask

What is AutoConfigureTestDatabase?

Annotation Type AutoConfigureTestDatabaseAnnotation that can be applied to a test class to configure a test database to use instead of the application-defined or auto-configured DataSource . In the case of multiple DataSource beans, only the @Primary DataSource is considered.

What is SpringBootTest annotation?

Spring Boot provides a @SpringBootTest annotation, which can be used as an alternative to the standard spring-test @ContextConfiguration annotation when you need Spring Boot features. The annotation works by creating the ApplicationContext used in your tests through SpringApplication .

What is spring DataSource initialization mode?

Spring Boot automatically creates the schema of an embedded DataSource . This behaviour can be customized by using the spring.datasource.initialization-mode property. For instance, if you want to always initialize the DataSource regardless of its type: spring.datasource.initialization-mode=always.


2 Answers

Actually, I think you want this:

@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD) 

http://docs.spring.io/autorepo/docs/spring-framework/4.2.6.RELEASE/javadoc-api/org/springframework/test/annotation/DirtiesContext.html

@DirtiesContext may be used as a class-level and method-level annotation within the same class. In such scenarios, the ApplicationContext will be marked as dirty after any such annotated method as well as after the entire class. If the DirtiesContext.ClassMode is set to AFTER_EACH_TEST_METHOD, the context will be marked dirty after each test method in the class.

You put it on your Test class.

like image 183
Raphael Amoedo Avatar answered Sep 28 '22 18:09

Raphael Amoedo


Using the accepted answer in Spring-Boot 2.2.0, I was seeing JDBC syntax errors related to constraints:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Constraint "FKEFFD698EA2E75FXEERWBO8IUT" already exists; SQL statement: alter table foo add constraint FKeffd698ea2e75fxeerwbo8iut foreign key (bar) references bar [90045-200]

To fix this, I added @AutoConfigureTestDatabase to my unit test (part of spring-boot-test-autoconfigure):

import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.boot.test.context.SpringBootTest; import org.junit.runner.RunWith; import org.springframework.test.context.junit4.SpringRunner;   @RunWith(SpringRunner.class) @SpringBootTest @DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD) @AutoConfigureTestDatabase(replace = Replace.ANY) public class FooRepositoryTest { ... } 
like image 26
Zack Avatar answered Sep 28 '22 17:09

Zack