All checks were successful
news-summary-bot-cicd / build_push_deploy (push) Successful in 11m43s
138 lines
4.5 KiB
Python
138 lines
4.5 KiB
Python
"""discord.py 유닛 테스트 — 파싱, 비디오 ID 추출, 임베드 구성."""
|
|
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
|
|
from app.discord import _extract_video_id, _parse_summary, send_to_discord
|
|
|
|
|
|
# ── _extract_video_id ──
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"url, expected",
|
|
[
|
|
("https://youtu.be/abc123", "abc123"),
|
|
("https://www.youtube.com/watch?v=xyz789", "xyz789"),
|
|
("https://www.youtube.com/watch?v=xyz789&t=10", "xyz789"),
|
|
("https://youtu.be/abc123?si=something", "abc123"),
|
|
("https://example.com/no-video", None),
|
|
],
|
|
)
|
|
def test_extract_video_id(url: str, expected: str | None):
|
|
assert _extract_video_id(url) == expected
|
|
|
|
|
|
# ── _parse_summary ──
|
|
|
|
|
|
SAMPLE_SUMMARY_BOLD = """\
|
|
- **한줄 요약**: 한국 경제가 위기에 처했다.
|
|
|
|
- **주요 내용**:
|
|
- GDP 성장률 하락
|
|
- 수출 감소
|
|
- 환율 불안정
|
|
|
|
- **결론/시사점**: 정부의 적극적 대응이 필요하다.
|
|
"""
|
|
|
|
SAMPLE_SUMMARY_HEADING = """\
|
|
## 한줄 요약
|
|
한국 경제가 위기에 처했다.
|
|
|
|
## 주요 내용
|
|
- GDP 성장률 하락
|
|
- 수출 감소
|
|
- 환율 불안정
|
|
|
|
## 결론/시사점
|
|
정부의 적극적 대응이 필요하다.
|
|
"""
|
|
|
|
|
|
def test_parse_summary_bold_format():
|
|
result = _parse_summary(SAMPLE_SUMMARY_BOLD)
|
|
assert "한줄요약" in result
|
|
assert "한국 경제가 위기에 처했다." in result["한줄요약"]
|
|
assert "주요내용" in result
|
|
assert "GDP 성장률 하락" in result["주요내용"]
|
|
assert "결론/시사점" in result or "결론시사점" in result
|
|
|
|
|
|
def test_parse_summary_heading_format():
|
|
result = _parse_summary(SAMPLE_SUMMARY_HEADING)
|
|
assert "한줄요약" in result
|
|
assert "한국 경제가 위기에 처했다." in result["한줄요약"]
|
|
assert "주요내용" in result
|
|
assert "GDP 성장률 하락" in result["주요내용"]
|
|
|
|
|
|
def test_parse_summary_empty():
|
|
result = _parse_summary("이건 파싱 안 되는 텍스트")
|
|
assert result == {}
|
|
|
|
|
|
# ── send_to_discord ──
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_to_discord_embed_structure():
|
|
"""send_to_discord가 올바른 임베드 구조로 웹훅을 호출하는지 확인."""
|
|
mock_response = AsyncMock()
|
|
mock_response.raise_for_status = lambda: None
|
|
|
|
with patch("app.discord.httpx.AsyncClient") as mock_client_cls:
|
|
mock_client = AsyncMock()
|
|
mock_client.post.return_value = mock_response
|
|
mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
|
|
mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
await send_to_discord(
|
|
title="테스트 영상",
|
|
video_url="https://youtu.be/abc123",
|
|
summary=SAMPLE_SUMMARY_BOLD,
|
|
)
|
|
|
|
mock_client.post.assert_called_once()
|
|
payload = mock_client.post.call_args[1]["json"]
|
|
|
|
embed = payload["embeds"][0]
|
|
assert "📰 테스트 영상" == embed["title"]
|
|
assert embed["url"] == "https://youtu.be/abc123"
|
|
assert embed["thumbnail"]["url"] == "https://img.youtube.com/vi/abc123/hqdefault.jpg"
|
|
assert embed["footer"]["text"] == "YouTube 뉴스 요약 봇"
|
|
assert "timestamp" in embed
|
|
|
|
# 필드 확인
|
|
field_names = [f["name"] for f in embed["fields"]]
|
|
assert "📋 주요 내용" in field_names
|
|
assert "🎯 결론 / 시사점" in field_names
|
|
assert "🔗 원본 영상" in field_names
|
|
|
|
# description에 한줄 요약 포함
|
|
assert "한국 경제가 위기에 처했다" in embed["description"]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_to_discord_fallback_on_unparsable():
|
|
"""파싱 실패 시 전체 summary가 description에 들어가는지 확인."""
|
|
mock_response = AsyncMock()
|
|
mock_response.raise_for_status = lambda: None
|
|
|
|
with patch("app.discord.httpx.AsyncClient") as mock_client_cls:
|
|
mock_client = AsyncMock()
|
|
mock_client.post.return_value = mock_response
|
|
mock_client_cls.return_value.__aenter__ = AsyncMock(return_value=mock_client)
|
|
mock_client_cls.return_value.__aexit__ = AsyncMock(return_value=False)
|
|
|
|
raw = "이건 섹션 없는 요약 텍스트입니다."
|
|
await send_to_discord("테스트", "https://youtu.be/abc", raw)
|
|
|
|
payload = mock_client.post.call_args[1]["json"]
|
|
embed = payload["embeds"][0]
|
|
assert embed["description"] == raw
|
|
assert len(embed["fields"]) == 1
|
|
assert embed["fields"][0]["name"] == "🔗 원본 영상"
|