261 lines
6.7 KiB
C#
261 lines
6.7 KiB
C#
|
|
using Service.Budget;
|
|||
|
|
|
|||
|
|
namespace WebApi.Test.Budget;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// BudgetItemCalculator 单元测试
|
|||
|
|
/// 测试明细项计算用金额的各种规则
|
|||
|
|
/// </summary>
|
|||
|
|
public class BudgetItemCalculatorTest : BaseTest
|
|||
|
|
{
|
|||
|
|
[Fact]
|
|||
|
|
public void 收入项实际已发生_应返回实际值()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 10000m;
|
|||
|
|
var actualAmount = 9500m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Income,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: false,
|
|||
|
|
isArchived: false,
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(9500m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 收入项实际未发生_应返回预算值()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 5000m;
|
|||
|
|
var actualAmount = 0m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Income,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: false,
|
|||
|
|
isArchived: false,
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(5000m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 支出项普通情况_应返回MAX预算和实际()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 2000m;
|
|||
|
|
var actualAmount = 2500m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: false,
|
|||
|
|
isArchived: false,
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(2500m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 支出项未超预算_应返回预算值()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 2000m;
|
|||
|
|
var actualAmount = 1800m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: false,
|
|||
|
|
isArchived: false,
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(2000m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 支出项超预算_应返回实际值()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 2000m;
|
|||
|
|
var actualAmount = 2500m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: false,
|
|||
|
|
isArchived: false,
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(2500m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 支出项硬性且实际为0_月度_应按天数折算()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 3000m;
|
|||
|
|
var actualAmount = 0m;
|
|||
|
|
var date = new DateTime(2026, 2, 15); // 2月共28天,当前15号
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: true,
|
|||
|
|
isArchived: false,
|
|||
|
|
date,
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
var expected = 3000m / 28 * 15; // ≈ 1607.14
|
|||
|
|
result.Should().BeApproximately(expected, 0.01m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 支出项硬性且实际为0_年度_应按天数折算()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 12000m;
|
|||
|
|
var actualAmount = 0m;
|
|||
|
|
var date = new DateTime(2026, 2, 15); // 2026年第46天(31+15)
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: true,
|
|||
|
|
isArchived: false,
|
|||
|
|
date,
|
|||
|
|
BudgetPeriodType.Year
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
var expected = 12000m / 365 * 46; // ≈ 1512.33
|
|||
|
|
result.Should().BeApproximately(expected, 0.01m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 支出项硬性且实际大于0_应返回MAX值()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 3000m;
|
|||
|
|
var actualAmount = 3200m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: true,
|
|||
|
|
isArchived: false,
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(3200m);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 归档数据_应直接返回实际值()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 2000m;
|
|||
|
|
var actualAmount = 1800m;
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: false,
|
|||
|
|
isArchived: true, // 归档数据
|
|||
|
|
new DateTime(2026, 2, 15),
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
result.Should().Be(1800m); // 归档数据直接返回实际值,不走MAX逻辑
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 闰年2月按天折算边界情况()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 3000m;
|
|||
|
|
var actualAmount = 0m;
|
|||
|
|
var date = new DateTime(2024, 2, 29); // 闰年2月29日
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: true,
|
|||
|
|
isArchived: false,
|
|||
|
|
date,
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
var expected = 3000m / 29 * 29; // = 3000
|
|||
|
|
result.Should().Be(expected);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[Fact]
|
|||
|
|
public void 平年2月按天折算边界情况()
|
|||
|
|
{
|
|||
|
|
// Arrange
|
|||
|
|
var budgetLimit = 3000m;
|
|||
|
|
var actualAmount = 0m;
|
|||
|
|
var date = new DateTime(2026, 2, 28); // 平年2月28日
|
|||
|
|
|
|||
|
|
// Act
|
|||
|
|
var result = BudgetItemCalculator.CalculateEffectiveAmount(
|
|||
|
|
BudgetCategory.Expense,
|
|||
|
|
budgetLimit,
|
|||
|
|
actualAmount,
|
|||
|
|
isMandatory: true,
|
|||
|
|
isArchived: false,
|
|||
|
|
date,
|
|||
|
|
BudgetPeriodType.Month
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// Assert
|
|||
|
|
var expected = 3000m / 28 * 28; // = 3000
|
|||
|
|
result.Should().Be(expected);
|
|||
|
|
}
|
|||
|
|
}
|