Quartz 集成测试和事务

Posted

技术标签:

【中文标题】Quartz 集成测试和事务【英文标题】:Quartz Integration test and transactions 【发布时间】:2021-12-08 06:24:38 【问题描述】:

我尝试在 Quartz 调度程序上创建集成测试。

我有 2 个表:eventstasks。调度程序通过 event 通过 cron 触发器创建 task

@SneakyThrows
@Test
public void taskGenerationBeanTest() 
    RequestData request = requestBuilder(str(), str(), str()).build();
    String orderId = String.valueOf(UUID.randomUUID());
    Event event1 = getEvent("type1", request, orderId);
    Event event2 = getEvent("type2", request, orderId);

    eventRepository.save(event1);
    eventRepository.save(event2);

    Thread.sleep(20000);
    List<Event> events = eventRepository.findAll();
    Thread.sleep(1000);
    List<Task> actual = taskRepository.findAll();

    assertAll(
            () -> assertEquals(2, actual.size()),
            () -> assertTrue(actual.stream().anyMatch(t ->
                    "type1".equals(t.getEvent().getEventType()))),
            () -> assertEquals(event1.getOrderId(), actual.get(0).getEvent().getOrderId())
    );

首先,我得到了异常:

无法初始化代理 - 没有会话

我使用这个答案Spring Data JPA - "could not initialize proxy - no Session" - With Methods marked as transactional 并添加spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true 到我的测试配置。 所以现在我遇到了另一个问题 - 我的测试有时会成功,但更多时候它会失败,因为它只创建 1 个任务

方法,由Quartz执行:

@Override
@Transactional(isolation = Isolation.REPEATABLE_READ)
public int createAndSaveTasks(EventType eventType) 
    List<Task> tasks = eventService.getEvent(eventType)
            .stream()
            .map(Task::new)
            .collect(Collectors.toList());
    taskRepository.saveAll(tasks);
    return tasks.size();

那么如何正确地使用 Quarts 和事务创建集成测试?

【问题讨论】:

很可能测试类没有事务,因此您无法获取 t.getEvent() 或 orderId() @Gurkanİlleez 添加 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true 后我可以从任务中获取事件 【参考方案1】:

测试类使用存储库的findAll方法,如果你尝试获取LAZY初始化方法,你会得到这个异常。

在断言中:

t.getEvent().getEventType() // can throw it
actual.get(0).getEvent() // can throw it

为避免这种情况,您可以将其设为事务性或优先获取类型。

在 REPEATABLE READ 下,第二个 SELECT 保证至少显示从第一个 SELECT 返回的行不变。并发事务可以在那一分钟内添加新行,但不能删除或更改现有行。

Difference between "read commited" and "repeatable read"

【讨论】:

我做不到急切,因为一切正常,只有集成测试的问题 其实和隔离级别有关,可以改成READ_COMMITED。当 repeatable_read 时,第二个查询不能以并发方式更新

以上是关于Quartz 集成测试和事务的主要内容,如果未能解决你的问题,请参考以下文章

集成测试中的 Spring 事务管理

手撸golang GO与微服务 Saga模式之8 集成测试

如何在集成测试中使用 Propagation.REQUIRES_NEW 回滚嵌套事务

Quartz与Spring集成 Job如何自动注入Spring容器托管的对象

使用 Jooq 进行集成测试

涉及数据库读写的集成测试的最佳实践