JUnit测试触发java.lang.StackOverflowError求解决 | 单元测试新手求助
嘿,我看到你刚接触单元测试,遇到了StackOverflowError的问题,咱们一步步拆解解决,再聊聊测试用例的设计~
一、StackOverflowError的核心原因
你的测试类里有两个私有方法犯了无限递归的错误,直接导致栈溢出:
getDayWithNulls()方法内部第一行就调用了getDayWithNulls().setTrainings(null),这会不断调用自身,没有终止条件,最终耗尽栈空间。expectedDayWithAddedTrainingToNulls()也是同样的问题,方法内一直在递归调用自己,根本无法创建出有效的Day实例。
修正后的方法代码
把这两个方法改成先创建Day实例,再设置属性:
private Day getDayWithNulls() { Day day = new Day(); day.setTrainings(null); day.setMeasurements(null); day.setTrainingCycles(null); day.setDiets(null); day.setMeals(null); day.setLocalDate(LocalDate.now()); return day; } private Day expectedDayWithAddedTrainingToNulls() { Day day = new Day(); day.setTrainings(Collections.singletonList(getTrainingForTest())); day.setMeasurements(null); day.setTrainingCycles(null); day.setDiets(null); day.setMeals(null); day.setLocalDate(LocalDate.now()); return day; }
二、测试类的其他关键修复
- Mock方法行为未定义
你的addTraining方法依赖getActivityBoardDay(localDate, userId)获取Day对象,但你没有用Mockito定义这个方法的返回值,运行时会返回null,进而触发NullPointerException。需要在测试方法里补充Mock行为:
@Test public void addTraining_WhenTrainingsIsNull_AddsSuccessfully() { // 构造测试用的Day对象 Day testDay = getDayWithNulls(); // 定义Mock方法的返回值 when(databaseControllerMock.getActivityBoardDay(LocalDate.now(), userId)).thenReturn(testDay); // 执行待测试方法 Training testTraining = getTrainingForTest(); activitiesService.addTraining(userId, testTraining, LocalDate.now()); // 验证结果:注意要确保Day类正确实现了equals/hashCode,否则比较具体属性 Assert.assertEquals(Collections.singletonList(testTraining), testDay.getTrainings()); }
- @After方法的冗余操作
你的@After方法里的操作完全没必要,因为JUnit会在每次测试后自动清理测试上下文,@Before方法会重新创建activitiesService实例。可以直接删掉这个@After方法,或者改成重置Mock:
@After public void tearDown() throws Exception { reset(databaseControllerMock); }
三、关于测试用例的设计
你计划的三个测试用例非常合理,刚好覆盖addTraining方法的所有分支逻辑:
- 测试场景1:
Day的trainings列表为null时添加训练(你当前的测试) - 测试场景2:
Day的trainings列表为空(empty)时添加训练 - 测试场景3:
Day的trainings列表已有训练时,添加新训练
每个场景单独写一个测试方法,这样能清晰覆盖所有代码路径,也方便定位问题~
内容的提问来源于stack exchange,提问作者D.Zet
相关产品推荐
相关产品推荐

