test: 日终价格回归测试(日期窗口纯单测 + 新增可见性DB集成测试)
- EodPriceService 提取 static ResolveValueDateWindow(reqStart,reqEnd),使日期窗口逻辑可脱离数据库单测 - EodPriceDtoTest 新增4个纯单测:未传日期回退±1年、起止都填今天→仅今天窗口、显式区间原样生效、结束日今天上界为明天;锁定'页面始终5条'根因 - EodPriceGoldenReplayTest 新增 Record_NewRecordVisibility([Ignore]手动跑):直接跑 SearchUnderlyingList,锁定(a)今天+已上市可查 (b)日期0001查不出 (c)未上市查不出 - 构建0错误;EodPriceDtoTest 19通过0失败
This commit is contained in:
@@ -202,5 +202,53 @@ namespace YLErp.Modules.EodModule
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 日期窗口解析("页面始终5条"根因锁定,纯单测不连库)
|
||||
|
||||
[TestMethod]
|
||||
[Description("前端未传日期(年份<=2000) → 回退到 [今天-1年, 今天+1年)")]
|
||||
public void 未传日期_回退最近一年到明年()
|
||||
{
|
||||
var (start, end) = EodPriceService.ResolveValueDateWindow(DateTime.MinValue, DateTime.MinValue);
|
||||
Assert.AreEqual(DateTime.Today.AddYears(-1).Date, start.Date, "起始应回退到今天-1年");
|
||||
Assert.AreEqual(DateTime.Today.AddYears(1).Date, end.Date, "结束应回退到今天+1年");
|
||||
Assert.IsTrue(end > start, "窗口应正向");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[Description("列表页默认起止都填今天 → 窗口=[今天, 今天+1天),仅返回当天记录(即'5条'现象成因)")]
|
||||
public void 起止都填今天_窗口仅今天()
|
||||
{
|
||||
var today = DateTime.Today;
|
||||
var (start, end) = EodPriceService.ResolveValueDateWindow(today, today);
|
||||
Assert.AreEqual(today.Date, start.Date, "起始应为今天");
|
||||
Assert.AreEqual(today.AddDays(1).Date, end.Date, "结束应为今天+1天(半开区间含今天)");
|
||||
Assert.IsTrue(today >= start && today < end, "今天的记录应落入窗口");
|
||||
Assert.IsFalse(today.AddDays(-1) >= start && today.AddDays(-1) < end, "昨天的记录不应落入仅今天窗口");
|
||||
Assert.IsFalse(today.AddDays(1) >= start && today.AddDays(1) < end, "明天的记录不应落入仅今天窗口");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[Description("显式传区间(如近30天) → 原样生效,不被回退覆盖")]
|
||||
public void 显式区间_原样生效()
|
||||
{
|
||||
var start0 = DateTime.Today.AddDays(-30);
|
||||
var end0 = DateTime.Today;
|
||||
var (start, end) = EodPriceService.ResolveValueDateWindow(start0, end0);
|
||||
Assert.AreEqual(start0.Date, start.Date, "起始应等于传入");
|
||||
Assert.AreEqual(end0.AddDays(1).Date, end.Date, "结束应等于传入+1天");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[Description("结束日=今天 → 半开区间上界=今天+1天,今天当天记录可命中")]
|
||||
public void 结束日今天_上界为明天_当天可命中()
|
||||
{
|
||||
var (start, end) = EodPriceService.ResolveValueDateWindow(DateTime.Today.AddDays(-365), DateTime.Today);
|
||||
var today = DateTime.Today;
|
||||
Assert.IsTrue(today >= start && today < end, "今天记录应命中");
|
||||
Assert.IsFalse(today.AddDays(1) >= start && today.AddDays(1) < end, "明天记录不应命中");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,5 +187,78 @@ namespace YLErp.Modules.EodModule
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 回归:新增日终价格可见性(连真实库,标 [Ignore] 手动跑)
|
||||
|
||||
/// <summary>
|
||||
/// 回归"新增日终价格后是否查得出",直接跑生产查询 SearchUnderlyingList。
|
||||
/// 守护点(与之前"新增后查不出"的修复一一对应):
|
||||
/// (a) 今天 + 已上市(LaunchState=1) 标的 → 查得出;
|
||||
/// (b) 估值日期=0001(未填) → 落在列表默认"仅今天"窗口外 → 查不出;
|
||||
/// (c) 标的未上市(LaunchState!=1) → 被 inner join(underlying_manager.LaunchState=="1") 过滤 → 查不出。
|
||||
/// 复用库中已有标的(不新建 underlying_manager,避免触碰该表约束),只插入/清理临时债券估值行。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
[Ignore]
|
||||
[TestCategory("EodVisibility")]
|
||||
[Description("新增日终价格可见性:(a)今天+已上市可查 (b)日期0001查不出 (c)未上市查不出")]
|
||||
public void Record_NewRecordVisibility()
|
||||
{
|
||||
using (var db = DbContextFactory.GetYLDbContext())
|
||||
{
|
||||
var svc = new EodPriceService(OptUserInfo.SystemUser);
|
||||
var today = DateTime.Today;
|
||||
var req = new EodCommodityFuturePriceReq { ValueDateStart = today, ValueDateEnd = today };
|
||||
|
||||
// 取一个已上市的债券类标的(正向用例);退而求其次取任意已上市标的
|
||||
var listedBond = db.underlying_manager
|
||||
.FirstOrDefault(x => x.LaunchState == "1" && x.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CreditBonds)
|
||||
?? db.underlying_manager.FirstOrDefault(x => x.LaunchState == "1");
|
||||
Assert.IsNotNull(listedBond, "需存在一个 LaunchState=1 的标的用于正向回归");
|
||||
|
||||
// 取一个未上市的标的(负向用例)
|
||||
var unlisted = db.underlying_manager.FirstOrDefault(x => x.LaunchState != "1");
|
||||
Assert.IsNotNull(unlisted, "需存在一个 LaunchState!=1 的标的用于负向回归");
|
||||
|
||||
var insertedIds = new List<long>();
|
||||
try
|
||||
{
|
||||
// (a) 今天 + 已上市 → 查得出
|
||||
var a = new ChinaBondValuation { bond_id = listedBond.UnderlyingCode, valuation_date = today, dirty_price_close = 100, net_price = 100, yield = 3 };
|
||||
db.china_bond_valuation.Add(a);
|
||||
db.SaveChanges();
|
||||
insertedIds.Add(a.id);
|
||||
var rA = svc.SearchUnderlyingList(req);
|
||||
Assert.IsTrue(rA.rows.Any(x => x.id == a.id), "(a) 今天+已上市债券应查得出");
|
||||
|
||||
// (b) 日期=0001(未填) → 落在仅今天窗口外,查不出
|
||||
var b = new ChinaBondValuation { bond_id = listedBond.UnderlyingCode, valuation_date = DateTime.MinValue, dirty_price_close = 100, net_price = 100, yield = 3 };
|
||||
db.china_bond_valuation.Add(b);
|
||||
db.SaveChanges();
|
||||
insertedIds.Add(b.id);
|
||||
var rB = svc.SearchUnderlyingList(req);
|
||||
Assert.IsFalse(rB.rows.Any(x => x.id == b.id), "(b) 日期0001 应查不出");
|
||||
|
||||
// (c) 未上市标的 → 被 inner join 过滤,查不出
|
||||
var c = new ChinaBondValuation { bond_id = unlisted.UnderlyingCode, valuation_date = today, dirty_price_close = 100, net_price = 100, yield = 3 };
|
||||
db.china_bond_valuation.Add(c);
|
||||
db.SaveChanges();
|
||||
insertedIds.Add(c.id);
|
||||
var rC = svc.SearchUnderlyingList(req);
|
||||
Assert.IsFalse(rC.rows.Any(x => x.id == c.id), "(c) 未上市标的应查不出");
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var id in insertedIds)
|
||||
{
|
||||
var e = db.china_bond_valuation.Find(id);
|
||||
if (e != null) db.china_bond_valuation.Remove(e);
|
||||
}
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,24 @@ namespace YLErp.Modules.EodModule
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析日终价格列表的"估值日期"查询窗口。抽成 static 以便纯单测锁定行为(避免改坏)。
|
||||
/// 规则:
|
||||
/// - 起始日期年份 > 2000(前端传了有效日期)→ 用传入值;否则回退到 今天-1年。
|
||||
/// - 结束日期年份 > 2000 → 用传入值+1天(闭区间转半开);否则回退到 今天+1年。
|
||||
/// 注意:列表页默认把起止都设成"今天",于是窗口=[今天, 今天+1天)=仅今天 → 仅返回当天的记录
|
||||
/// (即"页面始终5条"现象的真正成因,非分页/查询 bug)。要看历史须把起始日期调早。
|
||||
/// </summary>
|
||||
public static (DateTime start, DateTime end) ResolveValueDateWindow(DateTime reqStart, DateTime reqEnd)
|
||||
{
|
||||
var start = reqStart.Year > 2000 ? reqStart : DateTime.Today.AddYears(-1);
|
||||
var end = reqEnd.Year > 2000 ? reqEnd.AddDays(1) : DateTime.Today.AddYears(1);
|
||||
return (start, end);
|
||||
}
|
||||
|
||||
public SearchListResult<EodUnderlyingPriceDto> SearchUnderlyingList(EodCommodityFuturePriceReq req)
|
||||
{
|
||||
var valueDtStart = req.ValueDateStart.Year > 2000 ? req.ValueDateStart : DateTime.Today.AddYears(-1);
|
||||
var valueDtEnd = req.ValueDateEnd.Year > 2000 ? req.ValueDateEnd.AddDays(1) : DateTime.Today.AddYears(1);
|
||||
var (valueDtStart, valueDtEnd) = ResolveValueDateWindow(req.ValueDateStart, req.ValueDateEnd);
|
||||
|
||||
var predicatUn = PredicateBuilder.Create<underlying_manager>(d => d.LaunchState == "1");
|
||||
var predicatEoc = PredicateBuilder.Create<eod_commodity_future_price>(source => source.ValueDate >= valueDtStart && source.ValueDate < valueDtEnd);
|
||||
|
||||
Reference in New Issue
Block a user