You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Timefold:如何对Variable Listener进行单元测试?

OptaPlanner VariableListener单元测试实现方案

一、这类单元测试是否必要?

非常有必要。自定义VariableListener的逻辑(比如跳过周末的时间计算)是任务调度规则的核心,直接决定任务的开始时间是否符合业务要求。单元测试可以:

  • 快速验证边界场景(如周五、周六、周日的时间处理)
  • 避免集成测试阶段才发现逻辑错误
  • 为后续逻辑修改提供回归测试保障

二、具体实现步骤

1. 准备依赖

确保项目中引入OptaPlanner测试依赖(以Maven为例):

<dependency>
    <groupId>org.optaplanner</groupId>
    <artifactId>optaplanner-test</artifactId>
    <version>${optaplanner.version}</version>
    <scope>test</scope>
</dependency>

同时引入JUnit 5作为测试框架。

2. 实例化核心测试对象

(1)创建规划实体与测试数据

先构造你的规划实体(例如FoodPackingTask)和对应的解决方案(例如FoodPackingSchedule),模拟真实业务场景的数据:

// 模拟前序任务
FoodPackingTask previousTask = new FoodPackingTask();
// 模拟当前任务,关联前序任务
FoodPackingTask currentTask = new FoodPackingTask();
currentTask.setPreviousTask(previousTask);

// 组装解决方案
FoodPackingSchedule solution = new FoodPackingSchedule();
solution.getTaskList().addAll(List.of(previousTask, currentTask));

(2)初始化ScoreDirector

通过OptaPlanner的TestScoreDirectorFactory创建ScoreDirector,它是触发VariableListener的核心上下文:

// 加载你的Solver配置文件
SolverFactory<FoodPackingSchedule> solverFactory = SolverFactory.createFromXmlResource("food-packing-solver-config.xml");
// 创建测试用的ScoreDirector工厂
TestScoreDirectorFactory<FoodPackingSchedule> testScoreDirectorFactory = TestScoreDirectorFactory.create(solverFactory);
// 构建ScoreDirector实例
ScoreDirector<FoodPackingSchedule> scoreDirector = testScoreDirectorFactory.buildScoreDirector();
// 将解决方案设置到ScoreDirector中
scoreDirector.setWorkingSolution(solution);

(3)实例化自定义VariableListener

直接创建你的监听器实例即可:

YourStartTimeVariableListener startTimeListener = new YourStartTimeVariableListener();

3. 触发监听器并验证逻辑

通过ScoreDirector的变量变更方法模拟真实场景下的监听器触发,然后验证结果是否符合预期:

示例:测试周五结束的前序任务

// 设置前序任务结束时间为周五17:00
LocalDateTime fridayEndTime = LocalDateTime.of(2024, 5, 17, 17, 0);
scoreDirector.beforeVariableChanged(previousTask, "endTime");
previousTask.setEndTime(fridayEndTime);
scoreDirector.afterVariableChanged(previousTask, "endTime");

// 验证当前任务的开始时间是否跳至下周一9:00(假设工作时间为周一至周五9:00-17:00)
LocalDateTime expectedStartTime = LocalDateTime.of(2024, 5, 20, 9, 0);
assertEquals(expectedStartTime, currentTask.getStartTime());

其他边界场景测试

  • 前序任务结束时间为周六:验证开始时间为下周一9:00
  • 前序任务结束时间为周四16:00:验证开始时间为周五9:00
  • 前序任务结束时间为周日23:00:验证开始时间为下周一9:00

4. 简化测试(可选)

如果监听器逻辑不依赖复杂的ScoreDirector上下文,也可以直接调用监听器的方法:

// 手动触发监听器
startTimeListener.afterVariableChanged(scoreDirector, currentTask, "previousTask");
// 验证结果
assertEquals(expectedStartTime, currentTask.getStartTime());

三、注意事项

  • 确保Solver配置文件中已正确注册你的VariableListener,否则TestScoreDirectorFactory无法识别
  • 测试用例要覆盖所有业务逻辑的边界场景,避免遗漏特殊情况
  • 如果监听器依赖其他变量或实体关系,测试时要完整模拟这些依赖

内容的提问来源于stack exchange,提问作者user23511321

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:15:30