Files
zszq-trs/UnitTestProject/Modules/TradeModule/TradeServiceBaseCloseNotionalCalcTest.cs
T
hjhan 21b86c871f test(trade): 补 23108016 互换/期权本次名义本金分支单元测试
抽 CalcSwapCloseNotionalFromEventData 和 CalcOptionCloseNotional 为 public static 纯函数, BuildTriggerContext 了结场景改为调用这两个函数. 新增 13 个单元测试覆盖: 互换分支 EventData null/空/非法JSON/正数/负数/零 容错与绝对值, 期权分支 两者null/单边null/正数相乘/负数容错 绝对值语义. 重点锁定静默 catch 容错契约, 防止 EventData 异常时名义本金变 0 绕过审批阈值.
2026-07-17 08:45:49 +08:00

134 lines
6.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using YLErp.DBModels;
using YLErp.Modules.TradeModule;
namespace YLErp.Modules.TradeModule
{
/// <summary>
/// TradeServiceBase.CalcSwapCloseNotionalFromEventData / CalcOptionCloseNotional 的回归测试。
/// ---------------------------------------------------------------
/// 守卫锦麟王提交 23108016 "BugFix 互换本次名义本金取错"。
///
/// 旧 bugBuildTriggerContext 了结场景统一用 trade_cash.UnwindPercentRate × 期初名义本金
/// 算本次名义本金,但收益互换的 trade_cash.UnwindPercentRate 口径与期权不同,
/// 导致互换审批触发条件用错本金,可能绕过/误触发审批阈值。
///
/// 修复:互换分支从 swap_event.EventData 反序列化取 CloseNotionalValue 绝对值;
/// 期权分支保留旧逻辑(期初名义本金 × UnwindPercentRate 绝对值)。
///
/// 抽出两个静态纯函数以支持无库单测,重点验证容错(null/空/非法 JSON)不会抛异常
/// 而是返回 0,避免静默吞异常导致名义本金为 0 进而绕过审批阈值。
/// </summary>
[TestClass]
public class TradeServiceBaseCloseNotionalCalcTest
{
// ================================================================
// 一、CalcSwapCloseNotionalFromEventData 容错与绝对值语义
// ================================================================
[TestMethod]
public void 互换_EventData为null_返回0_不抛异常()
{
var result = TradeServiceBase.CalcSwapCloseNotionalFromEventData(null);
Assert.AreEqual(0d, result, 0.0001, "null EventData 应容错返回 0");
}
[TestMethod]
public void 互换_EventData为空字符串_返回0_不抛异常()
{
var result = TradeServiceBase.CalcSwapCloseNotionalFromEventData("");
Assert.AreEqual(0d, result, 0.0001, "空字符串 EventData 应容错返回 0");
}
[TestMethod]
public void 互换_EventData为非法JSON_返回0_不抛异常()
{
// 旧实现 catch{} 静默吞异常,抽函数后必须保持此容错契约
var result = TradeServiceBase.CalcSwapCloseNotionalFromEventData("not-a-json");
Assert.AreEqual(0d, result, 0.0001, "非法 JSON 应被 catch 返回 0,不能抛异常");
}
[TestMethod]
public void 互换_EventData为合法JSON_正数CloseNotionalValue_原值返回()
{
var eventData = JsonConvert.SerializeObject(new UnwindData { CloseNotionalValue = 500_000m });
var result = TradeServiceBase.CalcSwapCloseNotionalFromEventData(eventData);
Assert.AreEqual(500_000d, result, 0.01, "正数 CloseNotionalValue 应原值返回");
}
[TestMethod]
public void 互换_EventData为合法JSON_负数CloseNotionalValue_取绝对值()
{
// 修复的核心契约:Math.Abs 取绝对值,防止方向反向导致名义本金变负
var eventData = JsonConvert.SerializeObject(new UnwindData { CloseNotionalValue = -500_000m });
var result = TradeServiceBase.CalcSwapCloseNotionalFromEventData(eventData);
Assert.AreEqual(500_000d, result, 0.01, "负数 CloseNotionalValue 应取绝对值返回 500000");
}
[TestMethod]
public void 互换_EventData为合法JSON_CloseNotionalValue为零_返回0()
{
var eventData = JsonConvert.SerializeObject(new UnwindData { CloseNotionalValue = 0m });
var result = TradeServiceBase.CalcSwapCloseNotionalFromEventData(eventData);
Assert.AreEqual(0d, result, 0.0001, "CloseNotionalValue=0 应返回 0");
}
// ================================================================
// 二、CalcOptionCloseNotional 容错与绝对值语义
// ================================================================
[TestMethod]
public void 期权_两者都为null_返回0()
{
var result = TradeServiceBase.CalcOptionCloseNotional(null, null);
Assert.AreEqual(0d, result, 0.0001, "两者 null 应返回 0");
}
[TestMethod]
public void 期权_期初名义本金为null_返回0()
{
var result = TradeServiceBase.CalcOptionCloseNotional(null, 0.5d);
Assert.AreEqual(0d, result, 0.0001, "originalStockEqvNotional=null 应返回 0");
}
[TestMethod]
public void 期权_平仓比例为null_返回0()
{
var result = TradeServiceBase.CalcOptionCloseNotional(1_000_000d, null);
Assert.AreEqual(0d, result, 0.0001, "unwindPercentRate=null 应返回 0");
}
[TestMethod]
public void 期权_两者都有值_正数相乘_返回乘积()
{
// 1,000,000 × 0.3 = 300,000
var result = TradeServiceBase.CalcOptionCloseNotional(1_000_000d, 0.3d);
Assert.AreEqual(300_000d, result, 0.01, "1M × 0.3 = 300K");
}
[TestMethod]
public void 期权_期初名义本金为负数_取绝对值后相乘()
{
// 异常但容错:-1,000,000 × 0.3 → Abs → 300,000
var result = TradeServiceBase.CalcOptionCloseNotional(-1_000_000d, 0.3d);
Assert.AreEqual(300_000d, result, 0.01, "期初名义本金为负数应取绝对值后相乘");
}
[TestMethod]
public void 期权_平仓比例为负数_取绝对值后相乘()
{
// 异常但容错:1,000,000 × -0.3 → Abs → 300,000
var result = TradeServiceBase.CalcOptionCloseNotional(1_000_000d, -0.3d);
Assert.AreEqual(300_000d, result, 0.01, "平仓比例为负数应取绝对值后相乘");
}
[TestMethod]
public void 期权_两者都为负数_取绝对值后相乘()
{
// -1,000,000 × -0.3 = 300,000(先乘后取 Abs,结果一致)
var result = TradeServiceBase.CalcOptionCloseNotional(-1_000_000d, -0.3d);
Assert.AreEqual(300_000d, result, 0.01, "两者都为负数应取绝对值后相乘");
}
}
}