DataGoKrParserTests.cs 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. using Infrastructure.StockData;
  2. namespace Application.Tests;
  3. [TestClass]
  4. public sealed class DataGoKrParserTests
  5. {
  6. [TestMethod]
  7. public void ParseDailyPrices_MapsFields_FromSampleJson()
  8. {
  9. // 금융위 주식시세정보(getStockPriceInfo) 표준 응답 샘플 — 실호출 불가 전제의 고정 문자열 검증
  10. const string json = """
  11. {"response":{"header":{"resultCode":"00","resultMsg":"NORMAL SERVICE."},"body":{"numOfRows":2,"pageNo":1,"totalCount":2,"items":{"item":[
  12. {"basDt":"20260702","srtnCd":"005930","isinCd":"KR7005930003","itmsNm":"삼성전자","mrktCtg":"KOSPI","clpr":"70500","vs":"-500","fltRt":"-.70","mkp":"71000","hipr":"71200","lopr":"70300","trqu":"12345678","trPrc":"870000000000","lstgStCnt":"5969782550","mrktTotAmt":"420870169275000"},
  13. {"basDt":"20260702","srtnCd":"A000660","isinCd":"KR7000660001","itmsNm":"SK하이닉스","mrktCtg":"KOSPI","clpr":"210000","vs":"3000","fltRt":"1.45","mkp":"208000","hipr":"211500","lopr":"207000","trqu":"2345678","trPrc":"490000000000","lstgStCnt":"728002365","mrktTotAmt":"152880496650000"}
  14. ]}}}}
  15. """;
  16. var (items, totalCount) = DataGoKrStockParser.ParseDailyPrices(json);
  17. Assert.AreEqual(2, totalCount);
  18. Assert.AreEqual(2, items.Count);
  19. var samsung = items[0];
  20. Assert.AreEqual("005930", samsung.Code);
  21. Assert.AreEqual(new DateOnly(2026, 7, 2), samsung.TradingDate);
  22. Assert.AreEqual(71000, samsung.Open);
  23. Assert.AreEqual(71200, samsung.High);
  24. Assert.AreEqual(70300, samsung.Low);
  25. Assert.AreEqual(70500, samsung.Close);
  26. Assert.AreEqual(12345678L, samsung.Volume);
  27. Assert.AreEqual(870000000000L, samsung.TradingValue);
  28. Assert.AreEqual(-500, samsung.ChangeAmount);
  29. Assert.AreEqual(-0.70m, samsung.ChangeRate, "-.70 형식 등락률을 파싱해야 한다");
  30. Assert.AreEqual(420870169275000L, samsung.MarketCap);
  31. Assert.AreEqual(5969782550L, samsung.ListedShares);
  32. Assert.AreEqual("000660", items[1].Code, "'A' 프리픽스 단축코드는 뒤 6자리로 정규화한다");
  33. }
  34. [TestMethod]
  35. public void ParseListedItems_SingleObjectItem_AndEmptyItems()
  36. {
  37. // 단건 응답은 item 이 배열이 아닌 객체로 온다
  38. const string single = """
  39. {"response":{"header":{"resultCode":"00","resultMsg":"NORMAL SERVICE."},"body":{"numOfRows":1,"pageNo":1,"totalCount":1,"items":{"item":
  40. {"basDt":"20260702","srtnCd":"005930","isinCd":"KR7005930003","itmsNm":"삼성전자","mrktCtg":"KOSPI","crno":"1301110006246","corpNm":"삼성전자(주)"}
  41. }}}}
  42. """;
  43. var (items, totalCount) = DataGoKrStockParser.ParseListedItems(single);
  44. Assert.AreEqual(1, totalCount);
  45. Assert.AreEqual(1, items.Count);
  46. Assert.AreEqual("005930", items[0].Code);
  47. Assert.AreEqual("KR7005930003", items[0].Isin);
  48. Assert.AreEqual("삼성전자", items[0].Name);
  49. Assert.AreEqual("KOSPI", items[0].MarketName);
  50. Assert.AreEqual(new DateOnly(2026, 7, 2), items[0].BaseDate);
  51. // 0건이면 items 가 빈 문자열로 온다
  52. const string empty = """
  53. {"response":{"header":{"resultCode":"00","resultMsg":"NORMAL SERVICE."},"body":{"numOfRows":0,"pageNo":1,"totalCount":0,"items":""}}}
  54. """;
  55. var (emptyItems, emptyTotal) = DataGoKrStockParser.ParseListedItems(empty);
  56. Assert.AreEqual(0, emptyTotal);
  57. Assert.AreEqual(0, emptyItems.Count);
  58. }
  59. [TestMethod]
  60. public void Parse_ErrorResultCode_Throws()
  61. {
  62. // 게이트웨이 정상 + 서비스 오류 코드 응답은 예외로 표면화한다 (조용한 빈 수집 방지)
  63. const string error = """
  64. {"response":{"header":{"resultCode":"30","resultMsg":"SERVICE_KEY_IS_NOT_REGISTERED_ERROR"},"body":null}}
  65. """;
  66. Assert.ThrowsExactly<InvalidOperationException>(() => DataGoKrStockParser.ParseListedItems(error));
  67. }
  68. }