- 删除 StubSwapDealService.GetConsumedInterest 的 硬编码(此前注释明写"与生产缺陷态一致",
等于把唯一会出错的机制整个屏蔽, 断言缺陷态输出, 伪绿)。
- 改为复用生产同一口径: 对真实收盘经 PersistFlowEvent 累积的 swap_flow_event
(EventType∈{互换,自动互换}, DataState=完成, EventDate<结算日) 求和 —— 数据来自真实代码执行, 非硬编码。
- TestableSwapEodPositionService 新增 FlowEvents 捕获 + override PersistFlowEvent, 供 GetConsumedInterest 真实计算(不连库)。
- 新增 E2EEodService: 从交易开始日(TradeDate)逐日驱动真实 SwapPositionCompose 构建 eod 链,
再把真实 eod 快照喂给平仓; 平仓走生产同一入口 SaveAutoEodWithCloseInterestPosition。
- 全程无硬编码输入: FR007 曲线/名义本金/日期均来自 Excel 场景真源, 计算全走真实代码。
- 验证: 24/24 通过(SKIP_INITIALIZATION); PrepaidPrincipal 追踪测试 2/2 通过; 基类改动无回归。
- 注: ConsumedInterestScenarioTest.CI_008 既有失败(复利重置日本金继承, 与本回合无关, 未触碰该文件), 另议。
88 lines
3.9 KiB
C#
88 lines
3.9 KiB
C#
using YLErp.DBModels;
|
||
using YLErp.DBModels.Enums;
|
||
using YLErp.Model;
|
||
|
||
namespace YLErp.Modules.SwapModule
|
||
{
|
||
/// <summary>
|
||
/// SwapEodPositionService 的可测试化基类(纯内存,不连库)。
|
||
/// ============================================================================
|
||
/// 收敛各 ScenarioTest 中 Stub 子类的重复 override:
|
||
/// - PersistEodSwapPosition:收集到列表,不写库
|
||
/// - SaveAllChanges:no-op
|
||
/// - GetCurrencyRate:返回 1.0(本币)
|
||
/// - 统一构造函数(注入 OptUserInfo,标记 UnitTest 来源)
|
||
///
|
||
/// 暴露 PersistedPositions / SaveChangesCount / ClientCashCalls 等输出捕获属性,
|
||
/// 供断言使用。各测试子类按需再 override 业务 seam(FindTrade/GetUnderlyingPrice 等)。
|
||
///
|
||
/// 设计原则:
|
||
/// - 只收敛 8/8 Stub 都重复的高频 override,不预设业务数据注入方式
|
||
/// (ComposePage 用属性字典、SwapPositionCompose 用构造函数 List,差异留给子类)
|
||
/// - 不提供 Execute* 包装器(签名各异且大多只出现 1-2 次,留在各子类避免基类膨胀)
|
||
/// ============================================================================
|
||
/// </summary>
|
||
public class TestableSwapEodPositionService : SwapEodPositionService
|
||
{
|
||
/// <summary>捕获所有持久化的 eod 持仓(按调用顺序)</summary>
|
||
public List<eod_swap_position> PersistedPositions { get; } = new();
|
||
|
||
/// <summary>
|
||
/// 捕获所有持久化的互换流水事件(按调用顺序)。
|
||
/// 生产 PersistFlowEvent 写 DbContext.swap_flow_event;GetConsumedInterest 也读同一张表。
|
||
/// 测试不连库,这里把真实收盘产生的 swap_flow_event 收集起来,
|
||
/// 使 GetConsumedInterest 能像生产一样从"真实累积的流水"里算已结利息,
|
||
/// 而无需硬编码、无需连库。这是消除"return 0m"伪绿的关键。
|
||
/// </summary>
|
||
public List<swap_flow_event> FlowEvents { get; } = new();
|
||
|
||
/// <summary>SaveAllChanges 调用次数</summary>
|
||
public int SaveChangesCount { get; private set; }
|
||
|
||
/// <summary>AddClientCash 调用记录(金额, 操作)</summary>
|
||
public List<(double amount, string action)> ClientCashCalls { get; } = new();
|
||
|
||
/// <summary>自增 id 模拟器(新增 eod 时分配 id)</summary>
|
||
private int _nextId = 1;
|
||
|
||
protected TestableSwapEodPositionService(string testName)
|
||
: base(new OptUserInfo(0, testName ?? nameof(TestableSwapEodPositionService), OptUserFrom.UnitTest))
|
||
{
|
||
}
|
||
|
||
// ===== 高频 seam override(8/8 Stub 都重复,收敛到基类)=====
|
||
|
||
protected override void PersistEodSwapPosition(eod_swap_position position)
|
||
{
|
||
if (position.id == 0) position.id = _nextId++;
|
||
PersistedPositions.Add(position);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 捕获真实收盘产生的 swap_flow_event(生产写 DbContext.swap_flow_event)。
|
||
/// 与 PersistEodSwapPosition 同理,这里只收集不写库,供 GetConsumedInterest 真实计算。
|
||
/// </summary>
|
||
protected override void PersistFlowEvent(swap_flow_event flowEvent)
|
||
{
|
||
if (flowEvent.id == 0) flowEvent.id = _nextId++;
|
||
FlowEvents.Add(flowEvent);
|
||
}
|
||
|
||
protected override void SaveAllChanges()
|
||
{
|
||
SaveChangesCount++;
|
||
}
|
||
|
||
protected override double GetCurrencyRate(string quoteCurrency, string settlementCurrency, DateTime valueDate, bool seekPreday, CurrencyRateType currencyRateType)
|
||
{
|
||
return 1.0; // 本币,汇率=1
|
||
}
|
||
|
||
protected override int AddClientCash(trade td, double amount, string action, DateTime valueDate)
|
||
{
|
||
ClientCashCalls.Add((amount, action));
|
||
return _nextId++;
|
||
}
|
||
}
|
||
}
|