KrxSriBondParserTests.cs 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using Infrastructure.StockData;
  2. namespace Application.Tests;
  3. [TestClass]
  4. public sealed class KrxSriBondParserTests
  5. {
  6. [TestMethod]
  7. public void ParseDaily_MapsIssuanceInfo_FromSampleJson()
  8. {
  9. // KRX OpenAPI(esg/sri_bond_info) 실검증 샘플 — 발행정보 스냅샷: ISU_CD 12자리 ISIN, 날짜 yyyyMMdd, 금액 원 단위, 표면이자율 %
  10. const string json = """
  11. {"OutBlock_1":[
  12. {"BAS_DD":"20250102","ISUR_NM":"신한은행","ISU_CD":"KR6000011B58","SRI_BND_TP_NM":"녹색채권","ISU_NM":"신한은행25-05-이10갑후(녹)","LIST_DD":"20210507","ISU_DD":"20210506","REDMPT_DD":"20310506","ISU_RT":"2.58000","ISU_AMT":"400000000000","LIST_AMT":"400000000000","BND_TP_NM":"회사채"}
  13. ]}
  14. """;
  15. var rows = KrxSriBondParser.ParseDaily(json);
  16. Assert.AreEqual(1, rows.Count);
  17. var r = rows[0];
  18. Assert.AreEqual("KR6000011B58", r.Code, "12자리 ISIN 원문 유지");
  19. Assert.AreEqual(new DateOnly(2025, 1, 2), r.TradeDate, "BAS_DD 스냅샷일");
  20. Assert.AreEqual("신한은행", r.IssuerName);
  21. Assert.AreEqual("녹색채권", r.SriBondType);
  22. Assert.AreEqual("신한은행25-05-이10갑후(녹)", r.Name);
  23. Assert.AreEqual(new DateOnly(2021, 5, 7), r.ListDate, "LIST_DD");
  24. Assert.AreEqual(new DateOnly(2021, 5, 6), r.IssueDate, "ISU_DD");
  25. Assert.AreEqual(new DateOnly(2031, 5, 6), r.RedemptionDate, "REDMPT_DD");
  26. Assert.AreEqual(2.58000m, r.CouponRate, "ISU_RT 표면이자율 %");
  27. Assert.AreEqual(400000000000L, r.IssueAmount, "ISU_AMT 발행금액(원)");
  28. Assert.AreEqual(400000000000L, r.ListAmount, "LIST_AMT 상장금액(원)");
  29. Assert.AreEqual("회사채", r.BondType);
  30. }
  31. [TestMethod]
  32. public void ParseDaily_MissingDatesAndRate_AreNull()
  33. {
  34. // 결측 방어 — 날짜/표면이자율/채권유형이 ""/"-" 이면 null. 천단위 콤마 금액 방어.
  35. const string json = """
  36. {"OutBlock_1":[
  37. {"BAS_DD":"20250102","ISUR_NM":"한국주택금융공사","ISU_CD":"KR350102GA30","SRI_BND_TP_NM":"사회적채권","ISU_NM":"주금공MBS","LIST_DD":"","ISU_DD":"-","REDMPT_DD":"","ISU_RT":"","ISU_AMT":"1,000,000,000","LIST_AMT":"-","BND_TP_NM":"-"}
  38. ]}
  39. """;
  40. var rows = KrxSriBondParser.ParseDaily(json);
  41. Assert.AreEqual(1, rows.Count);
  42. var r = rows[0];
  43. Assert.AreEqual("KR350102GA30", r.Code);
  44. Assert.IsNull(r.ListDate, "빈 LIST_DD 는 null");
  45. Assert.IsNull(r.IssueDate, "\"-\" ISU_DD 는 null");
  46. Assert.IsNull(r.RedemptionDate);
  47. Assert.IsNull(r.CouponRate, "빈 ISU_RT 는 null (0% 과 구분)");
  48. Assert.AreEqual(1000000000L, r.IssueAmount, "발행금액 콤마 제거");
  49. Assert.AreEqual(0L, r.ListAmount, "\"-\" LIST_AMT 는 0");
  50. Assert.IsNull(r.BondType, "\"-\" BND_TP_NM 은 null");
  51. }
  52. [TestMethod]
  53. public void ParseDaily_MissingCode_IsSkipped()
  54. {
  55. // 표준코드(ISU_CD) 없으면 UQ 키를 만들 수 없어 행 제외
  56. const string json = """
  57. {"OutBlock_1":[
  58. {"BAS_DD":"20250102","ISUR_NM":"발행사","ISU_CD":"","SRI_BND_TP_NM":"녹색채권","ISU_NM":"코드없음채권","ISU_AMT":"100","LIST_AMT":"100"}
  59. ]}
  60. """;
  61. Assert.AreEqual(0, KrxSriBondParser.ParseDaily(json).Count);
  62. }
  63. [TestMethod]
  64. public void ParseDaily_EmptyOrMissingBlock_ReturnsEmpty()
  65. {
  66. Assert.AreEqual(0, KrxSriBondParser.ParseDaily("""{"OutBlock_1":[]}""").Count);
  67. Assert.AreEqual(0, KrxSriBondParser.ParseDaily("""{"respMsg":"Unauthorized API Call","respCode":"401"}""").Count);
  68. }
  69. }