6

也许,我做错了什么,但我找不到以下情况的好方法。

我想对在下面使用Spring Batch执行作业的服务进行单元测试。这些作业通过预先配置AsyncTaskExecutor在单独的线程中执行。在我的单元测试中,我想:

  1. 创建几个域对象并通过 DAO 持久化它们
  2. 调用服务方法来启动作业
  3. 等到作业完成
  4. 使用 DAO 检索域对象并检查它们的状态

显然,以上所有内容都应该在一个事务中执行,但不幸的是,事务不会传播到新线程(我理解这背后的基本原理)。

我想到的想法:

  • 在步骤 (1) 之后提交事务#1。不好,因为 DB 状态应该在单元测试后回滚。
  • Isolation.READ_UNCOMMITTED在作业配置中使用。但这需要两种不同的配置用于测试和生产。
4

3 回答 3

2

我认为最简单的解决方案是在测试执行期间使用 SyncTaskExecutor 配置 JobLauncher - 这样作业在与测试相同的线程中执行并共享事务。

可以将任务执行器配置移动到单独的 spring 配置 xml 文件中。有两个版本 - 一个带有 SyncTaskExecutor,在测试期间使用,另一个 AsyncTaskExecutor 用于生产运行。

于 2011-04-24T15:34:30.820 回答
2

尽管这不是您问题的真正解决方案,但我发现可以手动在工作线程中启动新事务。在某些情况下,这可能就足够了。

资料来源:Spring 程序化事务

例子:

@PersistenceContext
private EntityManager entityManager;
@Autowired
private PlatformTransactionManager txManager;

/* in a worker thread... */
public void run() {
    TransactionStatus tx = txManager.getTransaction(new DefaultTransactionDefinition());
    try {
        entityManager.find(...)
        ...
        entityManager.flush(...)
        etc...
        txManager.commit(tx);
    } catch (RuntimeException e) {
        txManager.rollback(tx);
    }
}
于 2012-01-10T00:07:11.373 回答
1

如果您确实需要单独的配置,我建议您在配置中模板化隔离策略并从属性文件中获取其值,这样您就不会因为测试和生产而使用一组不同的 Spring 配置。

但我同意最好使用相同的策略生产用途。您的夹具数据有多大,如果有一个setUp()步骤吹走并重建您的数据(可能来自快照,如果它是大量数据)以便您不必依赖回滚,那会有多糟糕?

于 2011-03-08T12:27:52.483 回答