首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DBUnit和Spring在集成测试中请求时,可能不会导入或存在数据

DBUnit和Spring在集成测试中请求时,可能不会导入或存在数据
EN

Stack Overflow用户
提问于 2014-10-07 12:29:34
回答 1查看 7.1K关注 0票数 5

如果我使用以下设置运行dbunit,并在集成测试中通过HTTP请求数据,则不会获得任何数据,因为数据库是空的。DBUnit将数据写入数据库,但当我通过HTTP请求数据时,它是空的。

这是我的设置: Spring 1.1.7与spring starter(不包括tomcat)、spring starter、spring starter jpa、spring starter test、液基核心、dbunit 2.5.0、spring-test-dbunit 1.1.0。

主要应用课程:

代码语言:javascript
复制
@Configuration
@ComponentScan
@EnableAutoConfiguration
@RestController
@EnableTransactionManagement
@EnableJpaRepositories

测试配置(应用程序-test.yaml):

代码语言:javascript
复制
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

集成测试:

代码语言:javascript
复制
@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启动一起使用。也许执行监听器的工作方式与spring引导不一样?

我抛出了dbunit的类并读取了所有的调试日志输出,但是我没有理解它。DBUnit正在使用spring引导创建的dataSource (上面配置的),所以它是同一个数据库。

在启动集成测试时,会发生以下情况:

  • 清算基础基于清算基础配置创建数据库模式(也许jpa之前就已经推动了该模式?)
  • DBUnit插入到数据库中(例如日志输出和调试)
  • Get 404 not (当数据库中没有找到带有给定ID的条目时,我返回404 )

更新

我正在寻找一种替代dbunit的方法,但找不到任何好的解决方案。那么,如何为集成测试准备数据库呢?实际上,如果数据按预期持久化,我只需要在每次测试或测试之前导入个性化数据。

更新

我使用以下选项连接到h2数据库:

代码语言:javascript
复制
DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE

当我删除完整的spring .数据源.* configuration使用标准值创建数据源并启动内存中的h2数据库服务器时。这将在没有我提到的选项的情况下完成,我得到一个org.hibernate.PessimisticLockException,因为dbunit仍然锁定数据库表,并且在测试中发送的HTTP请求没有访问数据库表的权限。这是因为选项MVCC=true;增加了更高的并发性,基本上是什么问题,为什么没有数据:“只有连接‘查看’提交的数据,和自己的更改”。当通过HTTP请求访问数据库时,不存在dbunit的数据,因为dbunit的数据没有提交给spring连接.

那么,有人知道为什么h2 (以及derby)数据库表会被dbunit锁定吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-10 11:44:57

我终于找到了解决这个问题的办法。

我指出的PessimisticLockException的方向是正确的。DBUnit没有释放数据库连接,这就是为什么spring的连接无法访问锁定的数据库表。

我实现了自己的数据库操作。我使用了customize DBUnit database options选项。

首先,我基于TransactionOperation of DBUnit实现了一个名为DBUnit的类,其不同之处在于,在将auto设置为false之前,删除了check jdbcConnection.getAutoCommit() == false并保存了auto提交值。提交之后,我将值设置为保存的值,使其具有与前面相同的状态:

代码语言:javascript
复制
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。

代码语言:javascript
复制
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);
    }
}

并将其添加到我的测试类中:

代码语言:javascript
复制
@DbUnitConfiguration(databaseOperationLookup = AutoCommitTransactionDatabaseLookup.class)

我不确定这是不是更多的黑客。对我的黑客有什么线索吗?

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26236039

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档