惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
IT之家
IT之家
Microsoft Security Blog
Microsoft Security Blog
博客园 - 司徒正美
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
D
DataBreaches.Net
B
Blog RSS Feed
博客园_首页
The GitHub Blog
The GitHub Blog
I
InfoQ
L
LangChain Blog
G
Google Developers Blog
M
MIT News - Artificial intelligence
美团技术团队
腾讯CDC
V
Visual Studio Blog
aimingoo的专栏
aimingoo的专栏
博客园 - 聂微东
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Apple Machine Learning Research
Apple Machine Learning Research
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
博客园 - 叶小钗

小松鼠的博客

记录一次线上k8s工作节点无法创建容器的问题排查思路与解决办法 记一次线上GoLang项目OOM排查过程 从LastPass转向拥抱开源KeePass的心路历程 故障定位与 AI 结合前后端编码实践 FileBeat收集nginx-ingress-controller日志 K8s云原生环境下文件描述符占用过高查询思路 2024年最新关闭火绒安全工具的开机自启方法 Kubernetes任务调度实践-Go语言实现Job和CronJob对比分析 离线更新k8s环境下的trivy漏洞库方法 使用Go语言接入Choerodon实现基于OAuth2的统一身份认证登录 在Vue2中自定义Switch组件并实现父子组件双向数据绑定 关于docker jdk1.8镜像中的GB18030-2022标准支持及验证 Go框架gin中的session存储gin-contrib-sessions和go-session 关于修改node_module中的源码问题记录 docker-compose网络和内网服务IP冲突问题 慎用存储过程:一条语句引发的数据库存储100%占用 Spring Boot中4种文件下载方法的实现 避坑-不能将specific类型的gitlab-runner改变为share类型 Docker compose中的MySQL主从复制模式和percona-toolkit工具使用 在minio中开启https访问以及使用rclone备份minio桶 在多机Docker环境下部署Choerodon的解决方案 Prometheus中Monitor添加对SpringBoot Actuator的Basic认证 在Nginx的容器镜像中隐藏Nginx的Server响应头 K8s中的两种nginx-ingress-controller及其区别 两个docker工具:runlike和whaler Grafana中的邮件报警和截图插件grafana-image-enderer K8s中externalName-service和services-without-selectors maven配置文件settings.xml中的一些概念总结 K8s中flexvolume插件驱动的安装 K8s中的coredns无法解析svc问题排查
解决Spring单元测试中因外键关联导致的失败integrity constra...
ycyin · 2020-09-08 · via 小松鼠的博客

2020年9月8日大约 3 分钟Springspring单元测试junit


前言

Spring单元测试中因外键关联导致的失败,每个用例单独运行都没有问题,可是一起运行,就出现下面的异常错误信息:integrity constraint violation: foreign key no action。

出现错误时使用的环境

  • spring:3.2.16.RELEASE
  • unitils:3.4.2 (unitils-core、unitils-spring、unitils-dbunit、unitils-inject)
  • hsqldb:2.3.2
  • hibernate3:3.6.5.Final

单元测试类继承UnitilsJUnit4,以使用unitils进行测试。查看UnitilsJUnit4的Runner为@RunWith(UnitilsJUnit4TestClassRunner.class)

@ContextConfiguration( {"classpath*:applicationContext.xml" }) //① 初始化Spring容器
@DataSet("/data.xls")
public class IServiceImplTest extends UnitilsJUnit4{

   @Autowired
   IService service;

   @Test
   public void testMethod() {
      // do something
   }
}

当进行单元测试时,每个用例单独运行都没有问题,可是一起运行,就出现下面的异常错误信息:integrity constraint violation: foreign key no action详细错误栈见下:

Caused by: org.unitils.core.UnitilsException: Error while executing DataSetLoadStrategy
	at org.unitils.dbunit.datasetloadstrategy.impl.BaseDataSetLoadStrategy.execute(BaseDataSetLoadStrategy.java:48)
	at org.unitils.dbunit.DbUnitModule.insertDataSet(DbUnitModule.java:342)
	at org.unitils.dbunit.DbUnitModule.insertDataSet(DbUnitModule.java:268)
	at org.unitils.dbunit.DbUnitModule.insertDataSet(DbUnitModule.java:187)
	... 17 more
Caused by: java.sql.BatchUpdateException: integrity constraint violation: foreign key no action; FKD5D67893BB8A6726 table: T_TEST_TABLENAME
	at org.hsqldb.jdbc.JDBCStatement.executeBatch(Unknown Source)
	at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
	at org.dbunit.database.statement.BatchStatement.executeBatch(BatchStatement.java:59)
	at org.dbunit.operation.DeleteAllOperation.execute(DeleteAllOperation.java:126)
	at org.dbunit.operation.CompositeOperation.execute(CompositeOperation.java:79)
	at org.unitils.dbunit.datasetloadstrategy.impl.CleanInsertLoadStrategy.doExecute(CleanInsertLoadStrategy.java:45)
	at org.unitils.dbunit.datasetloadstrategy.impl.BaseDataSetLoadStrategy.execute(BaseDataSetLoadStrategy.java:44)
	... 20 more

问题解决

很明显,这是由于批量更新时外键级联导致的问题,解决思路主要是要在执行单元测试前取消级联依赖,其实根据hsql官方文档这个级联依赖应该默认是false,是否是Hibernate将其设为True还有待证实。

  1. 编写一个类,继承AbstractTestExecutionListener实现自定义Listener,在beforeTestClass中取消级联依赖。具体如下:

    import org.dbunit.database.DatabaseDataSourceConnection;
    import org.dbunit.database.IDatabaseConnection;
    import org.springframework.test.context.TestContext;
    import org.springframework.test.context.support.AbstractTestExecutionListener;
    
    import javax.sql.DataSource;
    
    public class ForeignKeyDisabling extends AbstractTestExecutionListener {
        @Override
        public void beforeTestClass(TestContext testContext) throws Exception {
            testContext.getApplicationContext()
                    .getAutowireCapableBeanFactory()
                    .autowireBean(this);
            IDatabaseConnection dbConn = new DatabaseDataSourceConnection(
                    testContext.getApplicationContext().getBean(DataSource.class)
            );
            dbConn.getConnection().prepareStatement("SET DATABASE REFERENTIAL INTEGRITY FALSE").execute();
    
        }
    }
    
  2. 然后使用@TestExecutionListeners注解将这个自定义Listener作用到测试类上。

    注意:这里不能使用unitils进行测试了(unitils使用@RunWith(UnitilsJUnit4TestClassRunner.class)),这里需要使用@RunWith(SpringJUnit4ClassRunner.class)

    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.TestExecutionListeners;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
    import org.unitils.dbunit.annotation.DataSet;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import static org.junit.Assert.*;
    
    
    @ContextConfiguration( {"classpath*:applicationContext.xml" }) //① 初始化Spring容器
    @DataSet("/data.xls")
    @RunWith(SpringJUnit4ClassRunner.class) // 不能使用UnitilsJUnit4TestClassRunner
    @TestExecutionListeners(listeners = {
          ForeignKeyDisabling.class, //自定义的Listener
          DependencyInjectionTestExecutionListener.class // Spring自带的对测试类中的依赖进行注入的Listener
    })
    public class IServiceImplTest{
    
       @Autowired
       IService service;
    
       @Test
       public void testMethod() {
          // do something
       }
    }
    

再运行单元测试就没有问题了。

参考

  1. hsql官方文档-set database sql references statement
  2. spring3.2官方文档-AbstractTestExecutionListener
  3. stackoverflow上的相同问题
  4. 数据访问层单元测试遇到的问题
  5. Spring Runwith注解和TestExecutionListener使用解析