首页 文章

使用HSQLDB的TDD - 删除外键

提问于
浏览
9

我正在使用HSQLDB进行数据层集成测试,这很棒 . 但是,我发现我的外键约束妨碍了我的测试 . 例如,要在一个表上测试一个简单的选择,我必须将虚拟数据插入另外五个表中 . 这让我想扔东西 .

我在整个模型代码中都有JPA注释,并已配置Hibernate以在配置中重新创建模式(hbm2ddl.create-drop) . 生成表时,连接被正确解释为外键约束 .

我想要的是:

  • 最初不创建外键(理想,最干净),或

  • 找到一种以编程方式删除数据库中所有外键的方法(有点hacky但会完成工作)

如果它_____48440_ m使用Spring来自动测试这些测试 . 有问题的测试继承自AbstractTransactionalJUnit4SpringContextTests .

你怎么看?可以这样做吗?

5 回答

  • 0

    您可以使用以下指令停用FK约束:

    SET REFERENTIAL_INTEGRITY FALSE;
    

    您可以在测试方法之前通过JDBC Statement 执行它(并在之后将其设置回 TRUE ) .

  • 8

    尝试使用平面xml数据集测试我的DAO时遇到了同样的问题 . Config是DBunit HSQLDB 2.2.8 JUnit4 Spring JPA->一起导致

    java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no parent; FK13EE6CE6F09A6AAC table: ****
    

    通过实现扩展 AbstractTestExecutionListener 的侦听器,我找到了一个很好的解决方法 . 您可以指定在每次测试之前要采取的操作类型,在我们的示例中,禁用外键约束 . NOTE: the syntax may differ depending of the version of HSQLDB used.

    public class ForeignKeyDisabling extends AbstractTestExecutionListener {    
        @Override
        public void beforeTestClass(TestContext testContext) throws Exception {
            IDatabaseConnection dbConn = new DatabaseDataSourceConnection(
                    testContext.getApplicationContext().getBean(DataSource.class)
                    );
            dbConn.getConnection().prepareStatement("SET DATABASE REFERENTIAL INTEGRITY FALSE").execute();
    
        }
    }
    

    然后,您只需要在测试中已经存在的集合中添加此侦听器:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({"applicationContext-test.xml"})
    @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DataSetTestExecutionListener.class, ForeignKeyDisabling.class})
    
  • 0

    基于这个主题的灵感,我为这个问题创建了一些更强大的解决方案 . 关键是,我在运行测试时非常喜欢约束,所有其他解决方案都让它被禁用 . 此代码仅在数据集导入期间禁用它们,然后重新启用它们 . 并且可以轻松扩展以支持另一个数据库引擎:

    import com.github.springtestdbunit.DbUnitTestExecutionListener;
    import org.apache.log4j.Logger;
    import org.dbunit.database.DatabaseDataSourceConnection;
    import org.dbunit.database.IDatabaseConnection;
    import org.springframework.test.context.TestContext;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    /**
     * Class DisableForeignKeysDbUnitTestExecutionListener
     * Simple wrapper class around DbUnitTestExecutionListener, which - for the time of importing the database -
     * disables Foreign Key Constraints checks.
     * This class can be extended by simply overriding toggleForeignKeysConstraintsForDbEngine(Connection, String, boolean);
     * subclasses should always call super-implementation for default case.
     */
    public class DisableForeignKeysDbUnitTestExecutionListener
        extends DbUnitTestExecutionListener
    {
        private static final Logger logger = Logger.getLogger(DisableForeignKeysDbUnitTestExecutionListener.class);
        private Connection cachedDbConnection;
    
        @Override
        public void beforeTestMethod(TestContext testContext)
            throws Exception
        {
            this.toggleForeignKeysConstraints(testContext, false);
            super.beforeTestMethod(testContext);
            this.toggleForeignKeysConstraints(testContext, true);
        }
    
        /**
         * Method should perform query to disable foreign keys constraints or return false,
         * if it is not able to perform such query (e.g. unknown database engine)
         *
         * @param connection    Database connection
         * @param dbProductName Name of the database product (as reported by connection metadata)
         * @param enabled       Expected state of foreign keys after the call
         *
         * @return True, if there was suitable statement for specified engine, otherwise false
         *
         * @throws SQLException
         */
        protected boolean toggleForeignKeysConstraintsForDbEngine(Connection connection, String dbProductName, boolean enabled)
            throws SQLException
        {
            switch (dbProductName)
            {
                case "HSQL Database Engine":
                    connection.prepareStatement("SET DATABASE REFERENTIAL INTEGRITY " + (enabled ? "TRUE" : "FALSE"))
                              .execute();
                    return (true);
            }
            return (false);
        }
    
        private void toggleForeignKeysConstraints(TestContext testContext, boolean enabled)
        {
            try
            {
                Connection connection = this.getDatabaseConnection(testContext);
                String databaseProductName = connection.getMetaData().getDatabaseProductName();
                if (!this.toggleForeignKeysConstraintsForDbEngine(connection, databaseProductName, enabled))
                {
                    throw new IllegalStateException("Unknown database engine '" + databaseProductName +
                                                        "'. Unable to toggle foreign keys constraints.");
                }
            }
            catch (Throwable throwable)
            {
                logger.error("Unable to toggle Foreign keys constraints: " + throwable.getLocalizedMessage());
            }
        }
    
        synchronized private Connection getDatabaseConnection(TestContext testContext)
            throws SQLException
        {
            if (this.cachedDbConnection == null)
            {
                DataSource dataSource = testContext.getApplicationContext().getBean(DataSource.class);
                if (dataSource == null)
                {
                    throw new IllegalStateException("Unable to obtain DataSource from ApplicationContext. " +
                                                        "Foreign constraints will not be disabled.");
                }
    
                IDatabaseConnection dsConnection = new DatabaseDataSourceConnection(dataSource);
                this.cachedDbConnection = dsConnection.getConnection();
            }
    
            return (this.cachedDbConnection);
        }
    }
    
  • 2

    我会考虑花一些时间来创建几个灯具,可能还有DBUnit,你可以插入@Before .

    BTW,AbstractTransactionalJUnit4Test在Spring 3.0中已弃用

  • 9

    做快点:

    SET REFERENTIAL_INTEGRITY FALSE; 进入测试资源目录中的 import.sql 文件 .

    问题解决得很快很好:)

    以下是有关 import.sql http://christopherlakey.com/articles/import-sql.html的一些信息

相关问题