【问题标题】:@SQL one time per class@SQL 每堂课一次
【发布时间】:2015-03-19 19:13:06
【问题描述】:

我正在使用 spring 框架编写一些集成测试。对于不同的集成测试类,我有不同的 SQL 脚本。像这样的:

@ContextConfiguration(classes = ...)
@Sql("classpath:sportCenter-test.sql")
public class SportCenterResourceIT {
    ...
}

除了 SQL 脚本在 每个 测试之前执行,而不是每个类一次执行之外,一切都运行良好。我已经搜索了一段时间的 spring 文档,但我找不到与此类选项相关的内容。

谁能给我一个提示?

【问题讨论】:

  • 你的测试中有Before标签吗?
  • 请与测试方法共享您的 SportCenterResourceIT 类,不需要它们确实是什么,但我也想检查在测试方法之前是否有任何 @Sql 标记。
  • @erhun 我的测试中没有其他@Sql 标签。唯一的一个是班级级别的。
  • 您希望为您的测试加载的ApplicationContext 执行一次SQL 脚本吗?还是您真的希望您的 SQL 脚本在测试类之前只执行一次?
  • 我已经解决了这个问题,方法是使用脚本(在类级别)清除所有数据库条目。见spring documentation

标签: spring spring-mvc spring-test


【解决方案1】:

在类级别添加org.springframework.transaction.annotation.Transactional 注释将防止来自@Sql 脚本的任何更改在测试之间持续存在。所以你的代码变成了:

@ContextConfiguration(classes = ...)
@Sql("classpath:sportCenter-test.sql")
@Transactional
public class SportCenterResourceIT {
    ...
}

这种组合将产生以下结果:

  1. 您的@Sql 脚本将在每次测试之前运行
  2. 测试本身将运行
  3. 第 1 步或第 2 步中的任何数据库更改都将在每次测试结束时恢复

【讨论】:

  • @Sql 语句将运行,但由于我们设置了@Transactional,该语句将在未提交的事务中运行。那就是您的测试将无法访问数据,您的@Sql 语句插入或更新。
  • 我的 sql 脚本正在插入数据。当第二次测试运行时,再次加载 sql,这给了我一个主键约束异常。如何预防?
【解决方案2】:

我用这种方式解决问题:

@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@Sql("classpath:sql/DataForRouteTesting.sql")
public class MyTest {}

每次都会执行脚本,但没有冲突的主键。

【讨论】:

    【解决方案3】:

    如果我们想每个类执行一次 sql 脚本,我们可以在 setup 方法中执行该脚本,并在脚本为一个方法执行后将 flag 设置为 true,这样它就不会再次执行。 ` @自动连线 私有数据源数据库;

    私有静态布尔数据加载 = false;

    @Before
    public void setup() throws SQLException {
        if(!dataLoaded) {
            try (Connection con = database.getConnection()) {
                ScriptUtils.executeSqlScript(con, new ClassPathResource("path_to_script.sql"));
                dataLoaded = true;
            }
        }
    }`
    

    【讨论】:

      【解决方案4】:

      我通过将 sql 脚本放入名为 data.sqlsrc/test/resources 文件夹中解决了我的问题。该文件在每个集成测试启动时执行一次。为此,您需要删除 @Sql 注释。

      【讨论】:

      • 这比把脚本放到每个测试类中要好,但它并不能解决所有问题。在我的情况下,脚本仍然执行了多次。我的脚本是创建表,所以我通过添加“如果不存在”子句解决了这个问题
      【解决方案5】:

      您可以创建一个使用@BeforeAll 和@Sql("classpath:sportCenter-test.sql") 注释的空静态方法

      @BeforeAll
      @Sql("classpath:sportCenter-test.sql") 
      public static void initSql() {
          
      }
      

      【讨论】:

      • Spring 不会在 @BeforeAll 方法上看到 @Sql,只能在测试方法上看到。
      猜你喜欢
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      • 2013-08-02
      • 2022-08-14
      • 1970-01-01
      • 1970-01-01
      • 2019-10-28
      • 1970-01-01
      相关资源
      最近更新 更多