""" 日报查询 API 测试(GET /api/news/reports/ 与 /api/news/events/)。 通过 mock 数据库查询层(api.report.query.*),只验证视图层 参数解析 / 默认窗口 / 响应结构 / 错误处理,不依赖真实 MySQL。 """ from datetime import timedelta from unittest.mock import patch from django.test import TestCase from django.utils import timezone from rest_framework.test import APIClient class NewsReportsAPITest(TestCase): """GET /api/news/reports/ 日报查询""" def setUp(self): self.client = APIClient() self.url = '/api/news/reports/' @patch('api.report.query.fetch_reports', return_value=[]) def test_default_window_last_24h(self, mock_fetch): resp = self.client.get(self.url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.json(), []) kwargs = mock_fetch.call_args.kwargs now = timezone.now() self.assertEqual(kwargs['start_date'], (now - timedelta(hours=24)).date()) self.assertEqual(kwargs['end_date'], now.date()) self.assertIsNone(kwargs['report_type']) self.assertIsNone(kwargs['report_id']) @patch('api.report.query.fetch_reports', return_value=[{'id': 1, 'report_date': '2026-08-01', 'report_type': 'finance'}]) def test_report_type_and_date_range(self, mock_fetch): resp = self.client.get(self.url, { 'report_type': 'finance', 'start_date': '2026-07-01', 'end_date': '2026-08-03', }) self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()), 1) kwargs = mock_fetch.call_args.kwargs self.assertEqual(kwargs['report_type'], 'finance') self.assertEqual(str(kwargs['start_date']), '2026-07-01') self.assertEqual(str(kwargs['end_date']), '2026-08-03') @patch('api.report.query.fetch_reports') def test_detail_by_id(self, mock_fetch): mock_fetch.return_value = { 'id': 10, 'report_date': '2026-08-03', 'report_type': 'finance', 'events': [{'id': 1, 'title': '事件一'}], } resp = self.client.get(self.url, {'id': '10'}) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.json()['id'], 10) self.assertEqual(mock_fetch.call_args.kwargs['report_id'], 10) @patch('api.report.query.fetch_reports', return_value=None) def test_detail_not_found(self, mock_fetch): resp = self.client.get(self.url, {'id': '99999'}) self.assertEqual(resp.status_code, 404) self.assertIn('error', resp.json()) def test_invalid_report_type(self): resp = self.client.get(self.url, {'report_type': 'xxx'}) self.assertEqual(resp.status_code, 400) def test_invalid_date_format(self): resp = self.client.get(self.url, {'start_date': '2026/07/01'}) self.assertEqual(resp.status_code, 400) def test_invalid_id(self): resp = self.client.get(self.url, {'id': 'abc'}) self.assertEqual(resp.status_code, 400) def test_non_positive_id(self): resp = self.client.get(self.url, {'id': '0'}) self.assertEqual(resp.status_code, 400) @patch('api.report.query.fetch_reports', side_effect=RuntimeError('db down')) def test_query_error_500(self, mock_fetch): resp = self.client.get(self.url) self.assertEqual(resp.status_code, 500) self.assertIn('error', resp.json()) class NewsEventsAPITest(TestCase): """GET /api/news/events/ 重要事件聚合""" def setUp(self): self.client = APIClient() self.url = '/api/news/events/' @patch('api.report.query.fetch_important_events', return_value=[]) def test_defaults(self, mock_fetch): resp = self.client.get(self.url) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.json(), []) kwargs = mock_fetch.call_args.kwargs self.assertEqual(kwargs['days'], 7) self.assertEqual(kwargs['importance'], 4) self.assertEqual(kwargs['limit'], 100) self.assertIsNone(kwargs['report_type']) self.assertIsNone(kwargs['section']) @patch('api.report.query.fetch_important_events', return_value=[{'id': 1, 'title': '重要事件', 'importance': 5}]) def test_filters(self, mock_fetch): resp = self.client.get(self.url, { 'days': '3', 'importance': '5', 'report_type': 'intl', 'section': 'intl', 'limit': '10', }) self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()), 1) kwargs = mock_fetch.call_args.kwargs self.assertEqual(kwargs['days'], 3) self.assertEqual(kwargs['importance'], 5) self.assertEqual(kwargs['limit'], 10) self.assertEqual(kwargs['report_type'], 'intl') self.assertEqual(kwargs['section'], 'intl') def test_invalid_days(self): resp = self.client.get(self.url, {'days': 'abc'}) self.assertEqual(resp.status_code, 400) def test_days_out_of_range(self): resp = self.client.get(self.url, {'days': '0'}) self.assertEqual(resp.status_code, 400) def test_invalid_importance(self): resp = self.client.get(self.url, {'importance': '9'}) self.assertEqual(resp.status_code, 400) def test_invalid_section(self): resp = self.client.get(self.url, {'section': 'foo'}) self.assertEqual(resp.status_code, 400) def test_invalid_report_type(self): resp = self.client.get(self.url, {'report_type': 'xxx'}) self.assertEqual(resp.status_code, 400) @patch('api.report.query.fetch_important_events', side_effect=RuntimeError('db down')) def test_query_error_500(self, mock_fetch): resp = self.client.get(self.url) self.assertEqual(resp.status_code, 500) self.assertIn('error', resp.json())