|
|
@@ -0,0 +1,188 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.etotem.cfc.entity.HealthDataSourceRecord;
|
|
|
+import com.etotem.cfc.entity.HealthDimensionScore;
|
|
|
+import com.etotem.cfc.entity.HealthNormReference;
|
|
|
+import com.etotem.cfc.entity.HealthReport;
|
|
|
+import com.etotem.cfc.mapper.HealthDataSourceRecordMapper;
|
|
|
+import com.etotem.cfc.mapper.HealthNormReferenceMapper;
|
|
|
+import com.etotem.cfc.service.impl.DimensionScoreServiceImpl;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.springframework.boot.test.context.SpringBootTest;
|
|
|
+import org.springframework.boot.test.mock.mockito.MockBean;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
+import static org.mockito.ArgumentMatchers.*;
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
+
|
|
|
+@SpringBootTest
|
|
|
+public class DimensionScoreServiceImplTest {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private DimensionScoreServiceImpl dimensionScoreService;
|
|
|
+
|
|
|
+ @MockBean
|
|
|
+ private HealthDimensionScoreService scoreService;
|
|
|
+
|
|
|
+ @MockBean
|
|
|
+ private HealthNormReferenceMapper normMapper;
|
|
|
+
|
|
|
+ @MockBean
|
|
|
+ private HealthReportService healthReportService;
|
|
|
+
|
|
|
+ @MockBean
|
|
|
+ private HealthDataSourceRecordService dataSourceRecordService;
|
|
|
+
|
|
|
+ @MockBean
|
|
|
+ private DimensionEnergySyncService dimensionEnergySyncService;
|
|
|
+
|
|
|
+ private HealthDimensionScore score(Long memberId, String dimension, int scoreVal) {
|
|
|
+ HealthDimensionScore s = new HealthDimensionScore();
|
|
|
+ s.setMemberId(memberId);
|
|
|
+ s.setDimension(dimension);
|
|
|
+ s.setScore(scoreVal);
|
|
|
+ s.setPercentile(50);
|
|
|
+ s.setDataSource("MANUAL");
|
|
|
+ s.setTier(3);
|
|
|
+ s.setAssessDate(new java.sql.Date(System.currentTimeMillis()));
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
+ private HealthDimensionScore scoreWithDate(Long memberId, String dimension, int scoreVal, int daysAgo) {
|
|
|
+ HealthDimensionScore s = score(memberId, dimension, scoreVal);
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.add(Calendar.DAY_OF_YEAR, -daysAgo);
|
|
|
+ s.setAssessDate(new java.sql.Date(cal.getTimeInMillis()));
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getHealthDimension_aggregatesAll7Dimensions() {
|
|
|
+ Long memberId = 1L;
|
|
|
+ List<HealthDimensionScore> scores = Arrays.asList(
|
|
|
+ score(memberId, "growth", 80),
|
|
|
+ score(memberId, "sleep", 75),
|
|
|
+ score(memberId, "vision", 70),
|
|
|
+ score(memberId, "immunity", 85),
|
|
|
+ score(memberId, "nutrition", 78),
|
|
|
+ score(memberId, "gut", 82),
|
|
|
+ score(memberId, "exercise", 88)
|
|
|
+ );
|
|
|
+ when(scoreService.getLatestScores(memberId)).thenReturn(scores);
|
|
|
+ when(scoreService.getHistoryScores(eq(memberId), anyString(), eq(2)))
|
|
|
+ .thenReturn(Collections.emptyList());
|
|
|
+ when(normMapper.selectNorm(anyString(), anyString(), anyInt())).thenReturn(null);
|
|
|
+
|
|
|
+ var result = dimensionScoreService.getHealthDimension(memberId);
|
|
|
+
|
|
|
+ assertNotNull(result);
|
|
|
+ assertEquals(memberId, result.getMemberId());
|
|
|
+ assertEquals(7, result.getDimensions().size());
|
|
|
+ assertNotNull(result.getHealthIndex());
|
|
|
+ BigDecimal expectedIndex = BigDecimal.valueOf(80 + 75 + 70 + 85 + 78 + 82 + 88)
|
|
|
+ .divide(BigDecimal.valueOf(7), 2, RoundingMode.HALF_UP);
|
|
|
+ assertEquals(expectedIndex, result.getHealthIndex());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getHealthDimension_trendUp_whenScoreIncreasedBy5OrMore() {
|
|
|
+ Long memberId = 1L;
|
|
|
+ List<HealthDimensionScore> latest = Collections.singletonList(score(memberId, "growth", 85));
|
|
|
+ List<HealthDimensionScore> history = Arrays.asList(
|
|
|
+ scoreWithDate(memberId, "growth", 85),
|
|
|
+ scoreWithDate(memberId, "growth", 78)
|
|
|
+ );
|
|
|
+ when(scoreService.getLatestScores(memberId)).thenReturn(latest);
|
|
|
+ when(scoreService.getHistoryScores(eq(memberId), eq("growth"), eq(2))).thenReturn(history);
|
|
|
+ when(normMapper.selectNorm(anyString(), anyString(), anyInt())).thenReturn(null);
|
|
|
+
|
|
|
+ var result = dimensionScoreService.getHealthDimension(memberId);
|
|
|
+ var growthDim = result.getDimensions().stream()
|
|
|
+ .filter(d -> "growth".equals(d.getDimension())).findFirst().orElseThrow();
|
|
|
+
|
|
|
+ assertEquals("up", growthDim.getTrend());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getHealthDimension_trendDown_whenScoreDecreasedBy5OrMore() {
|
|
|
+ Long memberId = 1L;
|
|
|
+ List<HealthDimensionScore> latest = Collections.singletonList(score(memberId, "sleep", 65));
|
|
|
+ List<HealthDimensionScore> history = Arrays.asList(
|
|
|
+ scoreWithDate(memberId, "sleep", 65),
|
|
|
+ scoreWithDate(memberId, "sleep", 73)
|
|
|
+ );
|
|
|
+ when(scoreService.getLatestScores(memberId)).thenReturn(latest);
|
|
|
+ when(scoreService.getHistoryScores(eq(memberId), eq("sleep"), eq(2))).thenReturn(history);
|
|
|
+ when(normMapper.selectNorm(anyString(), anyString(), anyInt())).thenReturn(null);
|
|
|
+
|
|
|
+ var result = dimensionScoreService.getHealthDimension(memberId);
|
|
|
+ var sleepDim = result.getDimensions().stream()
|
|
|
+ .filter(d -> "sleep".equals(d.getDimension())).findFirst().orElseThrow();
|
|
|
+
|
|
|
+ assertEquals("down", sleepDim.getTrend());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getHealthDimension_trendStable_whenScoreChangeLessThan5() {
|
|
|
+ Long memberId = 1L;
|
|
|
+ List<HealthDimensionScore> latest = Collections.singletonList(score(memberId, "vision", 72));
|
|
|
+ List<HealthDimensionScore> history = Arrays.asList(
|
|
|
+ scoreWithDate(memberId, "vision", 72),
|
|
|
+ scoreWithDate(memberId, "vision", 74)
|
|
|
+ );
|
|
|
+ when(scoreService.getLatestScores(memberId)).thenReturn(latest);
|
|
|
+ when(scoreService.getHistoryScores(eq(memberId), eq("vision"), eq(2))).thenReturn(history);
|
|
|
+ when(normMapper.selectNorm(anyString(), anyString(), anyInt())).thenReturn(null);
|
|
|
+
|
|
|
+ var result = dimensionScoreService.getHealthDimension(memberId);
|
|
|
+ var visionDim = result.getDimensions().stream()
|
|
|
+ .filter(d -> "vision".equals(d.getDimension())).findFirst().orElseThrow();
|
|
|
+
|
|
|
+ assertEquals("stable", visionDim.getTrend());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getHealthDimension_trendStable_whenNoHistory() {
|
|
|
+ Long memberId = 1L;
|
|
|
+ List<HealthDimensionScore> latest = Collections.singletonList(score(memberId, "immunity", 90));
|
|
|
+ when(scoreService.getLatestScores(memberId)).thenReturn(latest);
|
|
|
+ when(scoreService.getHistoryScores(eq(memberId), eq("immunity"), eq(2))).thenReturn(Collections.emptyList());
|
|
|
+ when(normMapper.selectNorm(anyString(), anyString(), anyInt())).thenReturn(null);
|
|
|
+
|
|
|
+ var result = dimensionScoreService.getHealthDimension(memberId);
|
|
|
+ var immunityDim = result.getDimensions().stream()
|
|
|
+ .filter(d -> "immunity".equals(d.getDimension())).findFirst().orElseThrow();
|
|
|
+
|
|
|
+ assertEquals("stable", immunityDim.getTrend());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getHealthDimension_levelMapsCorrectly() {
|
|
|
+ Long memberId = 1L;
|
|
|
+ when(scoreService.getLatestScores(memberId)).thenReturn(Collections.emptyList());
|
|
|
+ when(scoreService.getHistoryScores(anyLong(), anyString(), anyInt())).thenReturn(Collections.emptyList());
|
|
|
+ when(normMapper.selectNorm(anyString(), anyString(), anyInt())).thenReturn(null);
|
|
|
+
|
|
|
+ var result = dimensionScoreService.getHealthDimension(memberId);
|
|
|
+
|
|
|
+ for (var dim : result.getDimensions()) {
|
|
|
+ if (dim.getScore() != null) {
|
|
|
+ if (dim.getScore().intValue() >= 85) {
|
|
|
+ assertEquals("excellent", dim.getLevel(), "score " + dim.getScore() + " should be excellent");
|
|
|
+ } else if (dim.getScore().intValue() >= 60) {
|
|
|
+ assertEquals("good", dim.getLevel(), "score " + dim.getScore() + " should be good");
|
|
|
+ } else if (dim.getScore().intValue() >= 40) {
|
|
|
+ assertEquals("fair", dim.getLevel(), "score " + dim.getScore() + " should be fair");
|
|
|
+ } else {
|
|
|
+ assertEquals("poor", dim.getLevel(), "score " + dim.getScore() + " should be poor");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|