DBUnit and Spring Boot - data cannot be imported or present at request in integration test

If I started dbunit with the following setup and requesting data via HTTP in the integration test, I did not receive any data because the database is empty. DBUnit writes data to the database, but it is empty when I request data via HTTP.

This is my setup: Spring Download 1.1.7 using spring-boot-starter-web (exclude tomcat), spring-boot-starter-jetty, spring-boot-starter-data-jpa, spring-boot-starter test, liquid base core, dbunit 2.5.0, spring -test-dbunit 1.1.0

The main class of the application:

@Configuration @ComponentScan @EnableAutoConfiguration @RestController @EnableTransactionManagement @EnableJpaRepositories 

Test configuration (application-test.yaml):

 logging.level.org.springframework: DEBUG logging.level.org.dbunit: DEBUG spring.jpa.properties.hibernate.hbm2ddl.auto: update spring.jpa.database: h2 spring.jpa.show-sql: true // setting these properties to access the database via h2 console spring.datasource.url: jdbc:h2:tcp://localhost/mem:my_db;DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE spring.datasource.username: sa spring.datasource.password: sa spring.datasource.driverClassName: org.h2.Driver spring.jpa.database-platform: org.hibernate.dialect.H2Dialect liquibase.change-log: classpath:/db/changelog/db-master.xml 

Integration Test:

 @ActiveProfiles("test") @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = HDImageService.class) @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DbUnitTestExecutionListener.class }) @WebAppConfiguration @IntegrationTest("server.port:0") @DatabaseSetup("/database_seed.xml") @DatabaseTearDown(value = "/database_tear_down.xml", type = DatabaseOperation.DELETE_ALL) // test @Test public void get_works() throws Exception { // given String url = host + port + "/my-resource/1"; // when ResponseEntity<String> response = template.getForEntity(url, String.class); // then assertThat(response.getStatusCode(), is(HttpStatus.OK)); } 

I could put everything else here, like entities, repository, controller, but these components work because I already write in the test through the embedded repository to the database and get it through HTTP. So the problem is importing through dbunit, which doesn't work ... I already successfully used dbunit in an earlier version, but not along with spring boot. Perhaps execution listeners do not work as they do with spring loading?

I debug dropped the dbunit classes and read all the output from the debug log, but I do not understand this. DBUnit uses the spring-loaded data source created (above), so it has the same database.

When you run integration tests, the following happens:
- Liquibase creates a database schema based on the Liquibase configuration (maybe jpa has already advanced the schema before?)
- DBUnit paste into the database (says log output and debugging)
- Get 404 not found (I return 404 when no records were found in the database with this ID)

Update

I am looking for an alternative to dbunit but cannot find a good solution. So, how do you prepare your database for your integration tests? In fact, I only need to import the data of individual users before each test or test, if the data is saved as expected.

Update

I use the following options to connect to the h2 database:

 DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE 

When I deleted the full spring.datasource. * configuration spring creates a data source with standard values ​​and starts the h2 database server in memory. This will be done without the parameters I mentioned, and get org.hibernate.PessimisticLockException because dbunit is still blocking the database table and the HTTP request that was sent inside the test does not have access to the database table. This is due to the option MVCC=true; , which added higher concurrency, which is basically the problem of why there is no data: "Only connections" see "loyal data and own changes." When accessing the database via an HTTP request, dbunit data is missing, since dbunit data is not transmitted for the spring connection ...

So does anyone know why the h2 database table (as well as the derby) is locked by dbunit?

+5
source share
1 answer

I finally found a solution to this problem.

This was the right direction with the PessimisticLockException that I pointed to. DBUnit did not release the database connection, so the connection from spring could not access the table (s) of the database where it is locked.

I performed my own database operation. I used the option to configure DBUnit database settings .

First of all, I implemented a class called AutoCommitTransactionOperation based on TransactionOperation DBUnit, with the difference that I deleted the jdbcConnection.getAutoCommit() == false check and saved the auto-commit value before setting auto commit to false. After committing, I returned the value back to the saved value in order to have the same state as before:

 public class AutoCommitTransactionOperation extends DatabaseOperation { private final DatabaseOperation _operation; public AutoCommitTransactionOperation(DatabaseOperation operation) { _operation = operation; } public static final DatabaseOperation AUTO_COMMIT_TRANSACTION(DatabaseOperation operation) { return new AutoCommitTransactionOperation(operation); } public void execute(IDatabaseConnection connection, IDataSet dataSet) throws DatabaseUnitException, SQLException { logger.debug("execute(connection={}, dataSet={}) - start", connection, dataSet); IDatabaseConnection databaseConnection = connection; Connection jdbcConnection = databaseConnection.getConnection(); boolean autoCommit = jdbcConnection.getAutoCommit(); jdbcConnection.setAutoCommit(false); try { _operation.execute(databaseConnection, dataSet); jdbcConnection.commit(); } catch (DatabaseUnitException e) { jdbcConnection.rollback(); throw e; } catch (SQLException e) { jdbcConnection.rollback(); throw e; } catch (RuntimeException e) { jdbcConnection.rollback(); throw e; } finally { jdbcConnection.setAutoCommit(autoCommit); } } } 

Then I created DatabaseLookup.

 public class AutoCommitTransactionDatabaseLookup extends DefaultDatabaseOperationLookup { @Override public org.dbunit.operation.DatabaseOperation get(DatabaseOperation operation) { if (operation == operation.CLEAN_INSERT) { return AutoCommitTransactionOperation.AUTO_COMMIT_TRANSACTION(org.dbunit.operation.DatabaseOperation.CLEAN_INSERT); } return super.get(operation); } } 

and added it to my test class:

 @DbUnitConfiguration(databaseOperationLookup = AutoCommitTransactionDatabaseLookup.class) 

I'm not sure what else to crack ... any hints of my hacking?

+5
source

Source: https://habr.com/ru/post/1204171/


All Articles