如果我使用以下设置运行dbunit并在集成测试中通过HTTP请求数据,我没有得到任何数据,因为数据库是空的。 DBUnit将数据写入数据库,但是当我通过HTTP请求数据时它是空的。
这是我的设置: Spring Boot 1.1.7 with spring-boot-starter-web(不包括tomcat),spring-boot-starter-jetty,spring-boot-starter-data-jpa,spring-boot-starter-test,liquibase-core,dbunit 2.5 .0,spring-test-dbunit 1.1.0
主要申请类:
@Configuration
@ComponentScan
@EnableAutoConfiguration
@RestController
@EnableTransactionManagement
@EnableJpaRepositories
测试配置(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
集成测试:
@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));
}
我可以在这里发布其他所有内容,例如实体,存储库,控制器......但是这些组件正在运行,因为我已经通过注入的存储库写入测试数据库并通过HTTP获取它。所以问题是通过dbunit导入,这是行不通的...我已经在较旧的预测中成功使用了dbunit,但没有与spring boot一起使用。也许执行监听器的工作方式与spring boot不相似?
我调试了dbunit的类并读取了所有的调试日志输出,但是我没有得到它。 DBUnit正在使用spring boot创建的dataSource(上面配置的),所以它是相同的数据库。
开始集成测试时,会发生以下情况:
- liquibase基于liquibase配置创建数据库模式(也许jpa之前已经推送了模式?)
- DBUnit插入数据库(表示日志输出和调试)
- 找不到404(当在具有给定ID的数据库中找不到条目时,我返回404)
更新:
我正在寻找dbunit的替代品,但找不到任何好的解决方案。那么如何为集成测试准备数据库呢?实际上,如果数据按预期持久存在,我只需要在每次测试或测试之前导入单个数据。
更新:
我使用以下选项连接到h2数据库:
DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE
当我删除完整的spring.datasource。*配置弹簧正在创建具有标准值的数据源并启动内存中的h2数据库服务器。这将在没有我提到的选项的情况下完成,我得到org.hibernate.PessimisticLockException
,因为dbunit仍然锁定数据库表,并且在测试中发送的HTTP请求无法访问数据库表。这是因为选项MVCC=true;
增加了更高的并发性,基本上是问题,为什么没有数据存在:“仅连接”参见'已提交的数据和自己的更改'。通过HTTP请求访问数据库时,dbunit的数据不存在,因为没有为spring连接提交dbunit的数据...
那么,有谁知道为什么h2(以及derby)数据库表被dbunit锁定了?
答案 0 :(得分:6)
我终于找到了解决这个问题的方法。
这是我指向PessimisticLockException
的正确方向。 DBUnit没有释放数据库连接,这就是为什么spring连接无法访问锁定的数据库表的原因。
我实现了自己的数据库操作。我使用customize DBUnit database options选项。
首先,我基于DBUnit的TransactionOperation
实现了一个名为AutoCommitTransactionOperation
的类,区别在于我在设置自动提交之前删除了检查jdbcConnection.getAutoCommit() == false
并保存了自动提交值为假。在提交之后,我将值设置回保存的值,以具有与之前相同的状态:
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);
}
}
}
然后我创建了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);
}
}
并将其添加到我的测试类中:
@DbUnitConfiguration(databaseOperationLookup = AutoCommitTransactionDatabaseLookup.class)
我不确定这是否更加黑客......对我的黑客有什么暗示?