using Domain.Entities.Stocks; using Infrastructure.StockData; using Microsoft.EntityFrameworkCore; namespace Application.Tests; /// /// SeibroDividendSyncService 의 DB 반영 로직(SeibroDividendImport) 통합 검증 — HTTP 는 파서 입력을 fixture 로 대체 /// (SeibroIssuerSyncTests 방식 미러링). 실제 SQL Server(LocalDB)로 UQ upsert 동작 확인. /// [TestClass] public sealed class SeibroDividendSyncTests { [TestMethod] public async Task UpsertSchedules_FromSampleXml_InsertsAll_ThenIdempotent() { // 기대 행위: getDivSchedulInfo fixture(9행) 전 행 insert → 동일 스냅샷 재실행은 무변경 (UQ IssucoCustno+RgtStdDt+SortCd) var rows = SeibroDivSchedulParser.Parse(SeibroXml.Parse(SeibroFixtures.Read("getDivSchedulInfo.xml"))); using (var db = TestDb.Create()) { var (inserted, updated) = await SeibroDividendImport.UpsertSchedulesAsync(db, rows, CancellationToken.None); Assert.AreEqual(rows.Count, inserted, "첫 실행은 전 행 insert"); Assert.AreEqual(0, updated); } using (var db = TestDb.Create()) { var (inserted, updated) = await SeibroDividendImport.UpsertSchedulesAsync(db, rows, CancellationToken.None); Assert.AreEqual(0, inserted, "동일 스냅샷 재실행은 insert 없음"); Assert.AreEqual(0, updated, "무변경 행은 update 로 세지 않는다"); var saved = await db.DividendSchedule.AsNoTracking().Where(c => c.IssucoCustno == 593 && c.RgtStdDt == new DateOnly(2018, 3, 31)).SingleAsync(); Assert.AreEqual(new DateOnly(2018, 3, 29), saved.XrgtDt); Assert.AreEqual("02", saved.RgtRsnDetailSortCd); } } [TestMethod] public async Task UpsertDividends_FromSampleXml_UpsertsByIsinAndDate() { // 기대 행위: getDivInfo fixture(18행) upsert(Isin+RgtStdDt). ISSUCO_CUSTNO 부재라도 Isin 으로 저장된다. var rows = SeibroDivInfoParser.Parse(SeibroXml.Parse(SeibroFixtures.Read("getDivInfo.xml"))); using (var db = TestDb.Create()) { var (inserted, _) = await SeibroDividendImport.UpsertDividendsAsync(db, rows, CancellationToken.None); Assert.AreEqual(18, inserted); } using (var db = TestDb.Create()) { var (inserted, updated) = await SeibroDividendImport.UpsertDividendsAsync(db, rows, CancellationToken.None); Assert.AreEqual(0, inserted, "재실행 idempotent"); Assert.AreEqual(0, updated); var saved = await db.Dividend.AsNoTracking().Where(c => c.Isin == "KR7005930003" && c.RgtStdDt == new DateOnly(2016, 12, 31)).SingleAsync(); Assert.AreEqual(27500m, saved.CashAllocAmt); Assert.AreEqual(1.53m, saved.MartpDivRate); Assert.AreEqual(new DateOnly(2017, 4, 24), saved.Th1PayTermBeginDt); } } [TestMethod] public async Task UpsertDividends_ChangedAmount_UpdatesRow() { var isin = $"KR7{Guid.NewGuid().ToString("N")[..9]}"; var date = new DateOnly(2022, 12, 31); var original = new List { new(isin, "테스트배당", "보통주", date, 500m, 0m, 100m, 1000m, 2.5m, null, null, false, false, null, null, null, null) }; var changed = new List { new(isin, "테스트배당", "보통주", date, 500m, 0m, 100m, 1500m, 3.0m, null, null, false, false, null, null, null, null) }; using (var db = TestDb.Create()) { await SeibroDividendImport.UpsertDividendsAsync(db, original, CancellationToken.None); } using (var db = TestDb.Create()) { var (inserted, updated) = await SeibroDividendImport.UpsertDividendsAsync(db, changed, CancellationToken.None); Assert.AreEqual(0, inserted); Assert.AreEqual(1, updated, "현금배당금·시가배당율 변경 → update"); var saved = await db.Dividend.AsNoTracking().Where(c => c.Isin == isin).SingleAsync(); Assert.AreEqual(1500m, saved.CashAllocAmt); } } [TestMethod] public async Task UpsertRightsBaseDates_FromSampleXml_UpsertsByNaturalKey() { // 기대 행위: getStddtInfo fixture(3행) upsert(회사번호+기준일+사유코드+세부유형) var rows = SeibroStddtParser.Parse(SeibroXml.Parse(SeibroFixtures.Read("getStddtInfo.xml"))); using (var db = TestDb.Create()) { var (inserted, _) = await SeibroDividendImport.UpsertRightsBaseDatesAsync(db, rows, CancellationToken.None); Assert.AreEqual(3, inserted); } using (var db = TestDb.Create()) { var (inserted, updated) = await SeibroDividendImport.UpsertRightsBaseDatesAsync(db, rows, CancellationToken.None); Assert.AreEqual(0, inserted, "재실행 idempotent"); Assert.AreEqual(0, updated); var saved = await db.RightsBaseDate.AsNoTracking().Where(c => c.IssucoCustno == 593 && c.RgtStdDt == new DateOnly(2016, 12, 31) && c.RgtRacd == "001").SingleAsync(); Assert.AreEqual("정기총회", saved.RgtRacdNm); } } }