强宝健康模块
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package com.accounting.util;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* 减重计划计算测试。
|
||||
*
|
||||
* <p>这块是「设置目标 → 每周该减多少」的核心算术,也是最容易出现
|
||||
* 边界问题的地方:同日、超期、目标比起始还重、除零。所以边界用例
|
||||
* 写得比正常用例还多。</p>
|
||||
*/
|
||||
class WeightPlanCalculatorTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("三个月 65→58kg:总减 7kg 分到 13 周,每周 0.54kg")
|
||||
void weeklyLossForThreeMonths() {
|
||||
LocalDate start = LocalDate.of(2026, 1, 1);
|
||||
LocalDate target = LocalDate.of(2026, 4, 1); // 90 天
|
||||
|
||||
int weeks = WeightPlanCalculator.totalWeeks(start, target);
|
||||
assertEquals(13, weeks);
|
||||
|
||||
BigDecimal weekly = WeightPlanCalculator.weeklyLoss(
|
||||
new BigDecimal("65"), new BigDecimal("58"), weeks);
|
||||
assertEquals(new BigDecimal("0.54"), weekly);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("总天数除不尽 7 时向上取整 —— 少算一周会让每周目标偏轻")
|
||||
void roundsUpPartialWeek() {
|
||||
// 8 天 = 1 周 + 1 天,应该算 2 周而不是 1 周
|
||||
assertEquals(2, WeightPlanCalculator.totalWeeks(
|
||||
LocalDate.of(2026, 1, 1), LocalDate.of(2026, 1, 9)));
|
||||
// 6 天算 1 周
|
||||
assertEquals(1, WeightPlanCalculator.totalWeeks(
|
||||
LocalDate.of(2026, 1, 1), LocalDate.of(2026, 1, 7)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("同日或倒填日期都算 1 周,不除零")
|
||||
void sameDayFallsBackToOneWeek() {
|
||||
LocalDate day = LocalDate.of(2026, 1, 1);
|
||||
|
||||
assertEquals(1, WeightPlanCalculator.totalWeeks(day, day));
|
||||
// 目标日期早于开始日期也不该崩
|
||||
assertEquals(1, WeightPlanCalculator.totalWeeks(day, day.minusDays(5)));
|
||||
|
||||
// 1 周减 7kg 是个荒谬的值,但必须是个数、不能是异常
|
||||
assertEquals(new BigDecimal("7.00"), WeightPlanCalculator.weeklyLoss(
|
||||
new BigDecimal("65"), new BigDecimal("58"), 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("目标比起始还重时每周应减为 0,不能是负数")
|
||||
void gainingWeightGivesZeroNotNegative() {
|
||||
// 负数会让进度条宽度算反、也会让「每周应减」显示成 -0.5kg
|
||||
assertEquals(BigDecimal.ZERO, WeightPlanCalculator.weeklyLoss(
|
||||
new BigDecimal("58"), new BigDecimal("65"), 13));
|
||||
assertEquals(BigDecimal.ZERO, WeightPlanCalculator.weeklyLoss(
|
||||
new BigDecimal("60"), new BigDecimal("60"), 13));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("理想体重曲线:第 0 周是起始体重,最后一周落在目标上")
|
||||
void idealCurveEndsAtTarget() {
|
||||
BigDecimal start = new BigDecimal("65");
|
||||
BigDecimal target = new BigDecimal("58");
|
||||
BigDecimal weekly = new BigDecimal("0.54");
|
||||
|
||||
assertEquals(new BigDecimal("65.0"),
|
||||
WeightPlanCalculator.idealWeightAt(start, target, weekly, 0));
|
||||
|
||||
// 第 13 周:65 - 0.54*13 = 57.98,低于目标 58 → 应该钉在 58
|
||||
assertEquals(new BigDecimal("58"),
|
||||
WeightPlanCalculator.idealWeightAt(start, target, weekly, 13));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("理想体重不会跌破目标 —— 否则参照线会穿到目标下方")
|
||||
void idealWeightNeverGoesBelowTarget() {
|
||||
BigDecimal target = new BigDecimal("58");
|
||||
// 刻意给一个过大的每周减重
|
||||
BigDecimal ideal = WeightPlanCalculator.idealWeightAt(
|
||||
new BigDecimal("65"), target, new BigDecimal("2.0"), 10);
|
||||
assertEquals(target, ideal);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("时间进度:未开始 0、进行中在 0~1、超期封顶 1.0")
|
||||
void timeProgressIsClamped() {
|
||||
LocalDate start = LocalDate.of(2026, 1, 1);
|
||||
LocalDate target = LocalDate.of(2026, 1, 11); // 10 天
|
||||
|
||||
// 还没开始
|
||||
assertEquals(0.0, WeightPlanCalculator.timeProgress(start, target,
|
||||
LocalDate.of(2025, 12, 20)));
|
||||
// 正中间
|
||||
assertEquals(0.5, WeightPlanCalculator.timeProgress(start, target,
|
||||
LocalDate.of(2026, 1, 6)), 0.001);
|
||||
// 已超期:封顶 1.0,不是 1.5 —— 进度条宽度不能溢出
|
||||
assertEquals(1.0, WeightPlanCalculator.timeProgress(start, target,
|
||||
LocalDate.of(2026, 3, 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("每周超过 1kg 会被标记成不健康")
|
||||
void flagsUnhealthyPace() {
|
||||
// 65→58 只用 3 周 = 每周 2.33kg
|
||||
BigDecimal weekly = WeightPlanCalculator.weeklyLoss(
|
||||
new BigDecimal("65"), new BigDecimal("58"), 3);
|
||||
assertTrue(weekly.compareTo(WeightPlanCalculator.HEALTHY_WEEKLY_LOSS_KG) > 0);
|
||||
|
||||
// 正常节奏不该被标
|
||||
BigDecimal healthy = WeightPlanCalculator.weeklyLoss(
|
||||
new BigDecimal("65"), new BigDecimal("58"), 13);
|
||||
assertFalse(healthy.compareTo(WeightPlanCalculator.HEALTHY_WEEKLY_LOSS_KG) > 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user