using Domain.Entities.Stocks; using Domain.Entities.Stocks.ValueObject; using Infrastructure.Persistence; using CalendarHandler = Application.Features.Api.Stocks.GetDividendCalendar.Handler; using CalendarQuery = Application.Features.Api.Stocks.GetDividendCalendar.Query; using StockDivHandler = Application.Features.Api.Stocks.GetStockDividends.Handler; using StockDivQuery = Application.Features.Api.Stocks.GetStockDividends.Query; namespace Application.Tests; [TestClass] public sealed class SeibroDividendQueryHandlerTests { [TestMethod] public async Task GetDividendCalendar_FiltersByPeriod_OrdersByRgtStdDtDesc() { // 기대 행위: from~to(RgtStdDt) 범위 필터 + 최신순 정렬. 범위 밖 일정은 제외. var custno = 700100 + Random.Shared.Next(1, 800); using var db = TestDb.Create(); await db.DividendSchedule.AddAsync(DividendSchedule.Create(custno, "칼렌더종목", "103", "02", new DateOnly(2025, 3, 31), "2", "1", "1", null, null, new DateOnly(2025, 3, 27), false)); await db.DividendSchedule.AddAsync(DividendSchedule.Create(custno, "칼렌더종목", "103", "02", new DateOnly(2025, 6, 30), "2", "3", "2", null, null, new DateOnly(2025, 6, 26), false)); await db.DividendSchedule.AddAsync(DividendSchedule.Create(custno, "칼렌더종목", "103", "02", new DateOnly(2024, 12, 31), "2", "1", "1", null, null, new DateOnly(2024, 12, 27), false)); await db.SaveChangesAsync(default); var handler = new CalendarHandler(db); var result = await handler.Handle(new CalendarQuery(new DateOnly(2025, 1, 1), new DateOnly(2025, 12, 31), 1, 20), default); Assert.IsTrue(result.IsSuccess); var mine = result.Value.List.Where(c => c.IssucoCustno == custno).ToList(); Assert.AreEqual(2, mine.Count, "2024-12-31 은 범위 밖 → 제외"); Assert.AreEqual(new DateOnly(2025, 6, 30), mine[0].RgtStdDt, "최신순"); Assert.AreEqual(new DateOnly(2025, 6, 26), mine[0].XrgtDt); Assert.AreEqual("2", mine[0].FixType); } [TestMethod] public async Task GetStockDividends_ByShortCode_JoinsScheduleForXrgtDt() { // 기대 행위: 단축코드 → Stock.ISIN·IssucoCustno 로 Dividend(Isin) + DividendSchedule(권리락일/확정구분) 결합 var custno = 700900 + Random.Shared.Next(1, 800); var code = $"71{Random.Shared.Next(1000, 9999)}"; var isin = $"KR7{code}003"; // 12자 표준 ISIN (KR7 + 단축코드6 + 003) using var db = TestDb.Create(); var stock = Stock.Create(code, "배당탭종목", StockMarket.KOSPI, new DateOnly(2020, 1, 2), isin: isin); stock.SetIssucoCustno(custno); await db.Stock.AddAsync(stock); await db.Dividend.AddAsync(Dividend.Create(isin, "배당탭종목", "보통주", new DateOnly(2024, 12, 31), 100m, 0m, 400m, 20000m, 1.8m, new DateOnly(2025, 4, 20), null, false, false, null, null, null, null)); await db.DividendSchedule.AddAsync(DividendSchedule.Create(custno, "배당탭종목", "103", "02", new DateOnly(2024, 12, 31), "2", "1", "1", null, null, new DateOnly(2024, 12, 27), false)); await db.SaveChangesAsync(default); var handler = new StockDivHandler(db); var result = await handler.Handle(new StockDivQuery(code, 1, 20), default); Assert.IsTrue(result.IsSuccess); Assert.AreEqual(isin, result.Value.Isin); Assert.AreEqual(1, result.Value.Total); var row = result.Value.List[0]; Assert.AreEqual(20000m, row.CashPerShare); Assert.AreEqual(1.8m, row.MarketDividendRate); Assert.AreEqual(new DateOnly(2025, 4, 20), row.CashPayDate); Assert.AreEqual(new DateOnly(2024, 12, 27), row.XrgtDt, "DividendSchedule 권리락일 결합"); Assert.AreEqual("1", row.FixType, "확정구분 결합"); } [TestMethod] public async Task GetStockDividends_ByIsin_WhenNoStockRow() { // 기대 행위: 단축코드가 Stock 에 없으면 입력을 ISIN 으로 간주해 Dividend 조회 (권리락일은 회사번호 미상이라 null) var isin = $"US{Random.Shared.Next(100000, 999999)}0009"; using var db = TestDb.Create(); await db.Dividend.AddAsync(Dividend.Create(isin, "ISIN직접조회", "보통주", new DateOnly(2023, 12, 31), null, 0m, 300m, 15000m, 2.1m, null, null, null, null, null, null, null, null)); await db.SaveChangesAsync(default); var handler = new StockDivHandler(db); var result = await handler.Handle(new StockDivQuery(isin, 1, 20), default); Assert.IsTrue(result.IsSuccess); Assert.AreEqual(isin, result.Value.Isin); Assert.AreEqual(1, result.Value.Total); Assert.IsNull(result.Value.List[0].XrgtDt, "Stock·회사번호 미상 → 권리락일 결합 불가"); } }