From d0c78ceb288437a4186e7acbb2c8cc4f2f8cfd17 Mon Sep 17 00:00:00 2001 From: cat_shark <1716967236@qq.com> Date: Sat, 30 May 2026 17:37:29 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E6=96=B0=E5=A2=9E=20StudySessionsServi?= =?UTF-8?q?ceImpl=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=20(10=20cases)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 覆盖场景:ONGOING/PAUSED 状态的消息返回、报告创建、 边界值、会话不存在异常、updateById 调用验证 --- .../impl/StudySessionsServiceImplTest.java | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 src/test/java/com/guo/learningprogresstracker/service/impl/StudySessionsServiceImplTest.java diff --git a/src/test/java/com/guo/learningprogresstracker/service/impl/StudySessionsServiceImplTest.java b/src/test/java/com/guo/learningprogresstracker/service/impl/StudySessionsServiceImplTest.java new file mode 100644 index 0000000..552b958 --- /dev/null +++ b/src/test/java/com/guo/learningprogresstracker/service/impl/StudySessionsServiceImplTest.java @@ -0,0 +1,213 @@ +package com.guo.learningprogresstracker.service.impl; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.guo.learningprogresstracker.entity.StudyReportsEntity; +import com.guo.learningprogresstracker.entity.StudySessionsEntity; +import com.guo.learningprogresstracker.enums.StudySessionStateEnum; +import com.guo.learningprogresstracker.mapper.StudyReportFragmentsMapper; +import com.guo.learningprogresstracker.mapper.StudyReportsMapper; +import com.guo.learningprogresstracker.mapper.StudySessionsMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDateTime; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class StudySessionsServiceImplTest { + + @Spy + @InjectMocks + private StudySessionsServiceImpl studySessionsService; + + @Mock + private StudyReportsMapper studyReportsMapper; + + @Mock + private StudyReportFragmentsMapper studyReportFragmentsMapper; + + @Mock + private StudySessionsMapper studySessionsMapper; + + @BeforeEach + void setUp() { + // stub updateById,避免调用真实的 getBaseMapper() + doReturn(true).when(studySessionsService).updateById(any()); + } + + private StudySessionsEntity createSession(String state, int minutesAgo) { + StudySessionsEntity session = new StudySessionsEntity(); + session.setSessionNum("SESSION_TEST"); + session.setSessionState(state); + session.setStartTime(LocalDateTime.now().minusMinutes(minutesAgo)); + session.setLastStartTime(LocalDateTime.now().minusMinutes(minutesAgo)); + session.setEffectiveTime(0); + session.setActualTime(0); + return session; + } + + private void mockGetOneOpt(StudySessionsEntity session) { + doReturn(Optional.of(session)).when(studySessionsService).getOneOpt(any(Wrapper.class)); + } + + /** + * 场景1:ONGOING 状态,有效时间 < 10分钟 → 返回提示消息 + */ + @Test + void endedStudySession_ongoing_lessThan10Min_shouldReturnMessage() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.ONGOING.name(), 5); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_TEST", "学习内容"); + + assertEquals("本次有效学习时间不足10分钟,不计入总学习时间", message); + assertEquals(0, session.getEffectiveTime(), "effectiveTime 应被清零"); + assertEquals(StudySessionStateEnum.ENDED.name(), session.getSessionState()); + verify(studyReportsMapper).insert(any(StudyReportsEntity.class)); + } + + /** + * 场景2:ONGOING 状态,有效时间 > 10分钟 → 返回 null(正常结束) + */ + @Test + void endedStudySession_ongoing_moreThan10Min_shouldReturnNull() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.ONGOING.name(), 15); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_TEST", "学习内容"); + + assertNull(message, "有效时间超过10分钟不应返回提示"); + assertTrue(session.getEffectiveTime() > 0, "effectiveTime 应保留"); + assertEquals(StudySessionStateEnum.ENDED.name(), session.getSessionState()); + } + + /** + * 场景3:PAUSED 状态,有效时间 < 10分钟 → 返回 null(PAUSED 不触发提示) + */ + @Test + void endedStudySession_paused_lessThan10Min_shouldReturnNull() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.PAUSED.name(), 5); + session.setEffectiveTime(5 * 60); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_TEST", "学习内容"); + + assertNull(message, "PAUSED 状态结束不返回提示(用户已主动暂停)"); + assertEquals(0, session.getEffectiveTime(), "effectiveTime 仍应被实体层清零"); + } + + /** + * 场景4:PAUSED 状态,有效时间 > 10分钟 → 返回 null,effectiveTime 保留 + */ + @Test + void endedStudySession_paused_moreThan10Min_shouldReturnNull() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.PAUSED.name(), 15); + session.setEffectiveTime(15 * 60); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_TEST", "学习内容"); + + assertNull(message); + assertTrue(session.getEffectiveTime() > 0, "effectiveTime 应保留"); + } + + /** + * 场景5:无论是否触发清零,学习报告都应正常创建 + */ + @Test + void endedStudySession_shouldAlwaysCreateReport() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.ONGOING.name(), 3); + mockGetOneOpt(session); + + studySessionsService.endedStudySession("SESSION_TEST", "测试报告内容"); + + verify(studyReportsMapper).insert(argThat(report -> + "SESSION_TEST".equals(((StudyReportsEntity) report).getSessionNum()) + && "测试报告内容".equals(((StudyReportsEntity) report).getContent()) + )); + } + + /** + * 场景6:ONGOING 状态,有效时间恰好 = 10分钟 → 有效时间保留(600 不 < 600) + */ + @Test + void endedStudySession_ongoing_exactly10Min_shouldReturnNull() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.ONGOING.name(), 10); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_TEST", "学习内容"); + + assertNull(message, "有效时间等于10分钟应保留(阈值为 < 600)"); + assertTrue(session.getEffectiveTime() >= 10 * 60, "effectiveTime 应保留"); + } + + /** + * 场景7:会话不存在 → 抛出异常 + */ + @Test + void endedStudySession_sessionNotFound_shouldThrowException() { + doReturn(Optional.empty()).when(studySessionsService).getOneOpt(any(Wrapper.class)); + + assertThrows(Exception.class, () -> + studySessionsService.endedStudySession("NOT_EXIST", "内容")); + } + + /** + * 场景8:ONGOING 状态,有效时间极短(1分钟) → 返回提示消息 + */ + @Test + void endedStudySession_ongoing_veryShortTime_shouldReturnMessage() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.ONGOING.name(), 1); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_TEST", "学习内容"); + + assertEquals("本次有效学习时间不足10分钟,不计入总学习时间", message); + assertEquals(0, session.getEffectiveTime()); + } + + /** + * 场景9:ONGOING 状态,刚开始就结束(effectiveTime ≈ 0) → 返回提示消息 + */ + @Test + void endedStudySession_ongoing_immediatelyEnded_shouldReturnMessage() throws Exception { + StudySessionsEntity session = new StudySessionsEntity(); + session.setSessionNum("SESSION_INSTANT"); + session.setSessionState(StudySessionStateEnum.ONGOING.name()); + session.setStartTime(LocalDateTime.now()); + session.setLastStartTime(LocalDateTime.now()); + session.setEffectiveTime(0); + session.setActualTime(0); + mockGetOneOpt(session); + + String message = studySessionsService.endedStudySession("SESSION_INSTANT", "内容"); + + assertEquals("本次有效学习时间不足10分钟,不计入总学习时间", message); + assertEquals(0, session.getEffectiveTime()); + } + + /** + * 场景10:确认 updateById 被调用(会话状态持久化) + */ + @Test + void endedStudySession_shouldCallUpdateById() throws Exception { + StudySessionsEntity session = createSession(StudySessionStateEnum.ONGOING.name(), 5); + mockGetOneOpt(session); + + studySessionsService.endedStudySession("SESSION_TEST", "内容"); + + verify(studySessionsService).updateById(session); + } +}