From 9349d582b6c6ef3447ce16eab39d5a730daa3c00 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Thu, 11 Sep 2025 21:23:39 +0800 Subject: [PATCH] 'commit' --- .../EducationDataController.cpython-310.pyc | Bin 0 -> 892 bytes ...YuanZaiYuanCountController.cpython-310.pyc | Bin 1172 -> 1020 bytes Model/EducationDataModel.py | 6 +- .../EducationDataModel.cpython-310.pyc | Bin 0 -> 7404 bytes Test/test_education_interfaces.py | 148 ++++++++++-------- 5 files changed, 86 insertions(+), 68 deletions(-) create mode 100644 Controller/__pycache__/EducationDataController.cpython-310.pyc create mode 100644 Model/__pycache__/EducationDataModel.cpython-310.pyc diff --git a/Controller/__pycache__/EducationDataController.cpython-310.pyc b/Controller/__pycache__/EducationDataController.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8fdf69f3c1ba4d3651189c01db88cc3430ca84c8 GIT binary patch literal 892 zcmY*X&ubGw6rP!#WRo^cV^I+CQ1G-ue^?Nts3^7v50+}d(j^eKJCnG&$%ffo+JsiB ztxBQQQw7_KEvVqZpi&VjdaxJ4|6nd2G-(PRJqfkG%~skDytn(_%=hMf-y5f;r3t~> z`1a+-X9b}jL9l5(;)hnyDg*UbN3KWbM1P zM;XX%{RTGv;l0`oVXM#I*4JM2whw4jP}q~la@@=C|8vR&$joRd6UZUs{o^JN^-)|; zXo_eCh-eLPn7=|IsQ%|%UvHYZ!;ZL>9`OqUMqyAmH@WGhFF6HIIJV72`oPTh@}0$! zNI{J_n0p)?nIh39LMXum$F`FZq9ow2Z96ta{x(hyXmP1#4c9Y@mLPx-!JPD?jmOn_ z;F?A%BpDUq%T$1@R4iyKxV6##K6eCiGIloaFyH3qgSX%Y1XC!1lQgEp2*GrR?hu^X F`3J+X7P0^U literal 0 HcmV?d00001 diff --git a/Controller/__pycache__/RuYuanZaiYuanCountController.cpython-310.pyc b/Controller/__pycache__/RuYuanZaiYuanCountController.cpython-310.pyc index 3d5b880e84409b296de1778b8a69461bb5408aa0..09b98a04f30d5ad90126be51e062fed7e51a6884 100644 GIT binary patch delta 314 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 literal 0 HcmV?d00001 diff --git a/Test/test_education_interfaces.py b/Test/test_education_interfaces.py index 63a8844..157e21a 100644 --- a/Test/test_education_interfaces.py +++ b/Test/test_education_interfaces.py @@ -4,6 +4,7 @@ import time # API基础URL BASE_URL = "http://localhost:8100/RuYuanZaiYuan" +EDUCATION_DATA_BASE_URL = "http://localhost:8100/EducationData" # 支持的教育阶段 test_education_stages = [ @@ -13,6 +14,9 @@ test_education_stages = [ ("senior", "高中") ] +# 测试年份 +test_years = [2023, 2022, 2024] + def test_school_chart_interface(): """测试获取教育阶段图表数据接口""" @@ -51,13 +55,23 @@ def test_school_chart_interface(): time.sleep(0.5) -def test_school_inschool_chart_interface(): - """测试获取在校人数图表数据接口""" - print("\n===== 测试 /school/inschool/chart 接口 =====") +# @router.get("/school/inschool/chart") +# async def get_in_school_chart_config( +# education_stage: str = Query(default="preschool", pattern="^(preschool|primary|junior|senior)$", +# description="教育阶段: preschool(学前), primary(小学), junior(初中), senior(高中)") +# ): +# return RuYuanZaiYuanModel.generate_in_school_education_config(education_stage) +# + + +def test_education_data_by_year(): + """测试获取指定年份教育数据接口""" + print("\n===== 测试 /EducationData/byYear 接口 =====") - for stage_code, stage_name in test_education_stages: - url = f"{BASE_URL}/school/inschool/chart?education_stage={stage_code}" - print(f"\n测试 {stage_name}({stage_code}) 数据:") + # 测试不同年份的数据 + for year in test_years: + url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={year}" + print(f"\n测试 {year} 年数据:") try: response = requests.get(url) @@ -68,17 +82,32 @@ def test_school_inschool_chart_interface(): print(f"响应数据: {json.dumps(data, ensure_ascii=False, indent=2)}") # 验证返回数据的基本结构 - assert "xAxis_data" in data, "返回数据缺少xAxis_data字段" - assert "series_data_0" in data, "返回数据缺少series_data_0字段(城区数据)" - assert "series_data_1" in data, "返回数据缺少series_data_1字段(镇区数据)" - assert "series_data_2" in data, "返回数据缺少series_data_2字段(乡村数据)" - assert "series_data_3" in data, "返回数据缺少series_data_3字段(总人数数据)" - assert "series_data_4" in data, "返回数据缺少series_data_4字段(2022年基数数据)" - assert "education_stage" in data, "返回数据缺少education_stage字段" - assert data["education_stage"] == stage_name, f"教育阶段名称不匹配,期望: {stage_name},实际: {data['education_stage']}" - - print(f"✅ {stage_name} 数据验证通过") + assert "code" in data, "返回数据缺少code字段" + assert "message" in data, "返回数据缺少message字段" + assert "data" in data, "返回数据缺少data字段" + assert data["code"] == 200, f"状态码不匹配,期望: 200,实际: {data['code']}" + assert isinstance(data["data"], list), "data字段应为列表类型" + # 验证数据内容 + if data["data"]: + # 检查每个数据项的结构 + for item in data["data"]: + assert "education_stage" in item, "数据项缺少education_stage字段" + assert "school_count" in item, "数据项缺少school_count字段" + assert "teacher_count_10k" in item, "数据项缺少teacher_count_10k字段" + assert "enrollment_count_10k" in item, "数据项缺少enrollment_count_10k字段" + assert "admission_count_10k" in item, "数据项缺少admission_count_10k字段" + + # 检查数值类型 + assert isinstance(item["school_count"], (int, float)), "school_count应为数值类型" + assert isinstance(item["teacher_count_10k"], (int, float)), "teacher_count_10k应为数值类型" + assert isinstance(item["enrollment_count_10k"], (int, float)), "enrollment_count_10k应为数值类型" + assert isinstance(item["admission_count_10k"], (int, float)), "admission_count_10k应为数值类型" + + print(f"✅ {year} 年数据验证通过,共包含 {len(data['data'])} 个教育阶段的数据") + else: + print(f"⚠️ {year} 年未返回数据") + except requests.exceptions.RequestException as e: print(f"❌ 请求失败: {e}") except AssertionError as e: @@ -87,64 +116,51 @@ def test_school_inschool_chart_interface(): # 添加短暂延迟,避免请求过于频繁 time.sleep(0.5) - -def test_default_parameters(): - """测试默认参数情况""" - print("\n===== 测试默认参数 =====") + # 测试边界值 + print("\n===== 测试边界值 =====") - # 测试默认参数下的school/chart接口 - url = f"{BASE_URL}/school/chart" + # 测试最小值年份 + min_year = 2015 + url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={min_year}" + print(f"\n测试最小值年份 {min_year}:") try: response = requests.get(url) response.raise_for_status() - data = response.json() - print(f"school/chart默认参数响应状态码: {response.status_code}") - print(f"school/chart默认教育阶段: {data.get('education_stage')}") - - # 测试默认参数下的school/inschool/chart接口 - url = f"{BASE_URL}/school/inschool/chart" - response = requests.get(url) - response.raise_for_status() - data = response.json() - print(f"school/inschool/chart默认参数响应状态码: {response.status_code}") - print(f"school/inschool/chart默认教育阶段: {data.get('education_stage')}") - - except Exception as e: - print(f"❌ 默认参数测试失败: {e}") - - -def test_invalid_parameters(): - """测试无效参数情况""" - print("\n===== 测试无效参数 =====") + print(f"响应状态码: {response.status_code}") + print(f"✅ 最小值年份测试通过") + except requests.exceptions.RequestException as e: + print(f"❌ 请求失败: {e}") - # 测试无效的教育阶段参数 - invalid_stage = "invalid_stage" - url = f"{BASE_URL}/school/chart?education_stage={invalid_stage}" + # 测试最大值年份 + max_year = 2028 + url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={max_year}" + print(f"\n测试最大值年份 {max_year}:") try: response = requests.get(url) - print(f"无效参数响应状态码: {response.status_code}") - if response.status_code == 422: # FastAPI参数验证失败的状态码 - print("✅ 无效参数正确被拒绝") + response.raise_for_status() + print(f"响应状态码: {response.status_code}") + print(f"✅ 最大值年份测试通过") + except requests.exceptions.RequestException as e: + print(f"❌ 请求失败: {e}") + + # 测试超出范围的年份 + invalid_year = 2030 + url = f"{EDUCATION_DATA_BASE_URL}/byYear?year={invalid_year}" + print(f"\n测试超出范围的年份 {invalid_year}:") + try: + response = requests.get(url) + if response.status_code == 422: # FastAPI的验证错误状态码 + print(f"响应状态码: {response.status_code}") + print(f"✅ 超出范围年份正确返回验证错误") else: - data = response.json() - print(f"无效参数处理结果: {json.dumps(data, ensure_ascii=False, indent=2)}") - - except Exception as e: - print(f"❌ 无效参数测试异常: {e}") - - -def run_all_tests(): - """运行所有测试""" - print("开始测试教育阶段接口...") - - # 运行各个测试函数 - test_school_chart_interface() - test_school_inschool_chart_interface() - test_default_parameters() - test_invalid_parameters() - - print("\n所有测试完成!") + print(f"❌ 期望状态码422,实际: {response.status_code}") + except requests.exceptions.RequestException as e: + print(f"❌ 请求失败: {e}") if __name__ == "__main__": - run_all_tests() \ No newline at end of file + # 测试原有接口 + # test_school_chart_interface() + + # 测试新添加的教育数据接口 + test_education_data_by_year() \ No newline at end of file