api_test_adjusted_body_weight_calculator.py•13.7 kB
import asyncio
import json
import sys
import os
from fastmcp import Client
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import MCP_SERVER_URL
async def test_adjusted_body_weight_calculator(client):
"""测试调整体重计算器的各种功能和边界条件"""
def print_header():
print("\n" + "=" * 60)
print("调整体重计算器测试套件")
print("=" * 60)
def print_test_case(i, test_case):
print(f"\n测试 {i:2d} | {test_case['name']}")
print(f"- {test_case['description']}")
print(f"- 输入参数: {test_case['params']}")
def print_validation_result(expected, actual, errors=None, warnings=None):
if expected == actual:
status = "✅ 通过"
else:
status = "❌ 失败"
expected_text = "有效" if expected else "无效"
actual_text = "有效" if actual else "无效"
print(f"- 验证结果: {status} (期望: {expected_text}, 实际: {actual_text})")
if errors:
print(f"- ⚠️ 错误: {errors}")
if warnings:
print(f"- ⚠️ 警告: {warnings}")
def print_calculation_result(data):
"""打印完整的计算结果"""
abw_value = data.get("value", "N/A")
unit = data.get("unit", "")
explanation = data.get("explanation", "")
metadata = data.get("metadata", {})
warnings = data.get("warnings", [])
# 基本结果
print(f"- 调整体重: {abw_value} {unit}")
# 详细信息
if metadata:
height_cm = metadata.get("height_cm")
height_inches = metadata.get("height_inches")
actual_weight = metadata.get("actual_weight")
ibw = metadata.get("ideal_body_weight")
sex = metadata.get("sex")
clinical_note = metadata.get("clinical_note")
print(f"- 身高: {height_cm} cm ({height_inches} inches)")
print(f"- 实际体重: {actual_weight} kg")
print(f"- 理想体重: {ibw} kg")
print(f"- 性别: {sex}")
print(f"- 临床意义: {clinical_note}")
# 警告信息
if warnings:
for warning in warnings:
print(f"- ⚠️ 警告: {warning}")
# 计算解释(截取前几行)
if explanation:
lines = explanation.split("\n")[:6]
print(f"- 计算过程:")
for line in lines:
if line.strip():
print(f" {line}")
def print_summary(passed, total):
success_rate = (passed / total) * 100 if total > 0 else 0
print(f"\n" + "=" * 60)
print(f"测试总结: {passed}/{total} 通过 ({success_rate:.1f}%)")
if passed == total:
print("🎉 所有测试通过!")
else:
print(f"❌ {total - passed} 个测试失败")
print("=" * 60)
# 测试用例定义
test_cases = [
# 1. 正常计算测试 - 男性
{
"name": "正常男性ABW计算",
"description": "标准身高体重的男性调整体重计算",
"params": {"height": 175, "weight": 80, "sex": "male"},
"expected_valid": True,
"expected_range": (65, 85), # 期望的ABW范围
},
# 2. 正常计算测试 - 女性
{
"name": "正常女性ABW计算",
"description": "标准身高体重的女性调整体重计算",
"params": {"height": 165, "weight": 70, "sex": "female"},
"expected_valid": True,
"expected_range": (55, 75),
},
# 3. 肥胖患者测试 - 男性
{
"name": "肥胖男性ABW计算",
"description": "显著超重男性的调整体重计算",
"params": {"height": 180, "weight": 120, "sex": "male"},
"expected_valid": True,
"expected_range": (85, 105),
},
# 4. 肥胖患者测试 - 女性
{
"name": "肥胖女性ABW计算",
"description": "显著超重女性的调整体重计算",
"params": {"height": 160, "weight": 100, "sex": "female"},
"expected_valid": True,
"expected_range": (65, 85),
},
# 5. 偏瘦患者测试 - 男性
{
"name": "偏瘦男性ABW计算",
"description": "体重偏轻男性的调整体重计算",
"params": {"height": 175, "weight": 55, "sex": "male"},
"expected_valid": True,
"expected_range": (55, 75),
},
# 6. 偏瘦患者测试 - 女性
{
"name": "偏瘦女性ABW计算",
"description": "体重偏轻女性的调整体重计算",
"params": {"height": 165, "weight": 45, "sex": "female"},
"expected_valid": True,
"expected_range": (45, 65),
},
# 7. 边界测试 - 最小身高
{
"name": "最小身高测试",
"description": "测试最小允许身高100cm",
"params": {"height": 100, "weight": 30, "sex": "female"},
"expected_valid": True,
"expected_range": (5, 15), # 调整期望范围,考虑到IBW为负值的情况
},
# 8. 边界测试 - 最大身高
{
"name": "最大身高测试",
"description": "测试最大允许身高250cm",
"params": {"height": 250, "weight": 150, "sex": "male"},
"expected_valid": True,
"expected_range": (120, 160),
},
# 9. 边界测试 - 最小体重
{
"name": "最小体重测试",
"description": "测试最小允许体重20kg",
"params": {"height": 150, "weight": 20, "sex": "female"},
"expected_valid": True,
"expected_range": (20, 40),
},
# 10. 边界测试 - 最大体重
{
"name": "最大体重测试",
"description": "测试最大允许体重300kg",
"params": {"height": 200, "weight": 300, "sex": "male"},
"expected_valid": True,
"expected_range": (150, 200),
},
# 11. 错误测试 - 身高过低
{
"name": "身高过低错误",
"description": "身高低于100cm应该报错",
"params": {"height": 99, "weight": 70, "sex": "male"},
"expected_valid": False,
"expected_error": "Height must be between 100 and 250 cm",
},
# 12. 错误测试 - 身高过高
{
"name": "身高过高错误",
"description": "身高高于250cm应该报错",
"params": {"height": 251, "weight": 70, "sex": "male"},
"expected_valid": False,
"expected_error": "Height must be between 100 and 250 cm",
},
# 13. 错误测试 - 体重过低
{
"name": "体重过低错误",
"description": "体重低于20kg应该报错",
"params": {"height": 170, "weight": 19, "sex": "female"},
"expected_valid": False,
"expected_error": "Weight must be between 20 and 300 kg",
},
# 14. 错误测试 - 体重过高
{
"name": "体重过高错误",
"description": "体重高于300kg应该报错",
"params": {"height": 170, "weight": 301, "sex": "female"},
"expected_valid": False,
"expected_error": "Weight must be between 20 and 300 kg",
},
# 15. 错误测试 - 性别无效
{
"name": "性别无效错误",
"description": "性别参数无效应该报错",
"params": {"height": 170, "weight": 70, "sex": "unknown"},
"expected_valid": False,
"expected_error": "Sex must be 'male' or 'female'",
},
# 16. 错误测试 - 缺少身高
{
"name": "缺少身高参数",
"description": "缺少必需的身高参数",
"params": {"weight": 70, "sex": "male"},
"expected_valid": False,
"expected_error": "Height is required",
},
# 17. 错误测试 - 缺少体重
{
"name": "缺少体重参数",
"description": "缺少必需的体重参数",
"params": {"height": 170, "sex": "male"},
"expected_valid": False,
"expected_error": "Weight is required",
},
# 18. 错误测试 - 缺少性别
{
"name": "缺少性别参数",
"description": "缺少必需的性别参数",
"params": {"height": 170, "weight": 70},
"expected_valid": False,
"expected_error": "Sex is required",
},
# 19. 精确计算验证 - 男性
{
"name": "精确计算验证(男性)",
"description": "验证男性ABW计算的精确性",
"params": {"height": 175, "weight": 90, "sex": "male"},
"expected_valid": True,
"expected_abw": 78.279, # 修正后的精确期望值
},
# 20. 精确计算验证 - 女性
{
"name": "精确计算验证(女性)",
"description": "验证女性ABW计算的精确性",
"params": {"height": 165, "weight": 80, "sex": "female"},
"expected_valid": True,
"expected_abw": 66.146, # 修正后的精确期望值
},
]
print_header()
passed_tests = 0
total_tests = len(test_cases)
for i, test_case in enumerate(test_cases, 1):
print_test_case(i, test_case)
try:
# 调用计算器
result = await client.call_tool("calculate", {"calculator_id": 62, "parameters": test_case["params"]})
# 使用 structured_content 或 data 属性获取实际数据
calc_data = result.structured_content or result.data or {}
if isinstance(calc_data, dict) and calc_data.get("success") and "result" in calc_data:
# 成功计算
data = calc_data["result"]
if test_case["expected_valid"]:
# 期望成功的测试
print_validation_result(True, True)
print_calculation_result(data)
# 验证计算结果范围
abw_value = data.get("value")
if "expected_range" in test_case:
min_val, max_val = test_case["expected_range"]
if min_val <= abw_value <= max_val:
print(f"- ✅ 结果在期望范围内: {min_val}-{max_val} kg")
passed_tests += 1
else:
print(f"- ❌ 结果超出期望范围: {min_val}-{max_val} kg")
elif "expected_abw" in test_case:
expected = test_case["expected_abw"]
if abs(abw_value - expected) < 0.5: # 允许0.5kg误差
print(f"- ✅ 计算结果准确: 期望 {expected} kg")
passed_tests += 1
else:
print(f"- ❌ 计算结果不准确: 期望 {expected} kg, 实际 {abw_value} kg")
else:
passed_tests += 1
else:
# 期望失败但计算成功
print_validation_result(False, True)
print(f"- ❌ 期望失败但计算成功")
else:
# 计算失败(可能是参数验证失败)
error_msg = calc_data.get("error", "未知错误") if isinstance(calc_data, dict) else str(calc_data)
if test_case["expected_valid"]:
# 期望成功但失败
print_validation_result(True, False, error_msg)
print(f"- ❌ 期望成功但计算失败")
else:
# 期望失败的测试
expected_error = test_case.get("expected_error", "")
print_validation_result(False, False, error_msg)
if expected_error in error_msg:
print(f"- ✅ 错误信息正确")
passed_tests += 1
else:
print(f"- ❌ 错误信息不匹配")
print(f" 期望包含: {expected_error}")
print(f" 实际错误: {error_msg}")
except Exception as e:
print(f"- ❌ 测试异常: {str(e)}")
print_summary(passed_tests, total_tests)
return passed_tests, total_tests
async def main():
"""主函数:连接到MCP服务器并运行测试"""
print("正在连接到调整体重计算器MCP服务器...")
try:
# 使用HTTP连接
async with Client(MCP_SERVER_URL) as client:
print("✅ 连接成功!")
# 运行测试
passed, total = await test_adjusted_body_weight_calculator(client)
# 最终结果
if passed == total:
print(f"\n🎉 所有 {total} 个测试都通过了!")
else:
print(f"\n❌ {total - passed} 个测试失败,共 {total} 个测试")
except Exception as e:
print(f"❌ 连接失败: {e}")
print("请确保MCP服务器正在运行在 http://127.0.0.1:9000")
if __name__ == "__main__":
asyncio.run(main())