如何对使用Stream流的Java业务方法进行单元测试?
首先你需要准备基础测试依赖,推荐使用JUnit 5 + Mockito组合,用来模拟依赖方法的返回值,避免测试受外部真实数据影响。如果你的项目用到JavaFX的ObservableList,可额外引入TestFX依赖解决JavaFX运行时测试问题。
你需要模拟的依赖方法包括服务类中的getAppointmentsForSpecificDoctor()、getAllAppointments(),单元测试时只验证你写的Stream逻辑正确性,不需要调用这两个方法的真实实现。
该方法逻辑为:过滤指定医生的所有预约,返回日期为当天的预约列表,可覆盖3个测试场景:
- 场景1:存在当天预约,返回正确过滤结果
构造3条测试预约数据,2条日期为当天、1条为其他日期,模拟
getAppointmentsForSpecificDoctor()返回这3条数据,断言返回的列表长度为2,且所有返回预约的日期均为当天。
- 场景2:无当天预约,返回空列表
构造的所有预约日期均不为当天,模拟依赖方法返回后,断言结果为空列表。
- 场景3:无任何预约数据,返回空列表
模拟
getAppointmentsForSpecificDoctor()返回空列表,断言结果为空。
该方法逻辑为:先过滤出姓名匹配的医生的所有预约,再过滤出指定日期的预约,最后提取时间字段返回,可覆盖4个测试场景:
- 场景1:存在对应医生对应日期的预约,返回正确时间列表
构造2个不同姓名医生的预约数据,其中目标医生有3条预约,2条属于指定日期,时间分别为
09:00、14:00,模拟getAllAppointments()返回所有构造数据,传入目标医生和指定日期调用方法,断言返回的列表长度为2,且包含两个目标时间。
- 场景2:对应医生无指定日期的预约,返回空列表
构造的目标医生预约均不在指定日期,断言返回结果为空。
- 场景3:无对应姓名的医生的预约,返回空列表
构造的所有预约中没有对应姓名的医生数据,断言返回结果为空。
- 场景4:无任何预约数据,返回空列表
模拟
getAllAppointments()返回空列表,断言结果为空。
@ExtendWith(MockitoExtension.class) public class AppointmentServiceTest { // 用@Spy注解测试真实服务类,仅模拟依赖的外部方法 @Spy private AppointmentService appointmentService; @Test void getAppointmentsForToday_HasTodayAppointments_ReturnsCorrectList() { // 固定测试时间,避免跨天测试失败 LocalDate testToday = LocalDate.of(2024, 5, 20); try (MockedStatic<LocalDate> mockedLocalDate = Mockito.mockStatic(LocalDate.class)) { mockedLocalDate.when(LocalDate::now).thenReturn(testToday); // 构造测试数据 Appointment app1 = new Appointment(testToday, new Doctor("张", "三")); Appointment app2 = new Appointment(testToday, new Doctor("张", "三")); Appointment app3 = new Appointment(testToday.plusDays(1), new Doctor("张", "三")); // 模拟依赖方法返回 doReturn(List.of(app1, app2, app3)).when(appointmentService).getAppointmentsForSpecificDoctor(); // 调用测试方法 List<Appointment> result = appointmentService.getAppointmentsForToday(); // 断言结果 assertEquals(2, result.size()); assertTrue(result.stream().allMatch(app -> app.getDate().equals(testToday))); } } }
- 时间稳定性:所有涉及
LocalDate.now()的测试,都建议固定返回值,不要用系统当前时间,避免跨天执行测试时结果不一致。 - 业务边界校验:第二个方法用医生
firstName做匹配规则,如果业务允许医生重名,当前逻辑会返回所有同名医生的预约,你可根据业务需求补充对应测试用例,验证逻辑是否符合预期。 - JavaFX依赖处理:如果测试环境没有启动JavaFX上下文,
FXCollections.observableArrayList()可能抛出异常,可引入TestFX框架解决,也可以直接把返回的ObservableList转成普通List做断言,不需要依赖JavaFX运行时特性。
内容的提问来源于stack exchange,提问作者sooope

