diff --git a/docs/API接口文档.md b/docs/API接口文档.md new file mode 100644 index 0000000..ae26b5b --- /dev/null +++ b/docs/API接口文档.md @@ -0,0 +1,378 @@ +# HospitalPay-Go Socket 服务器接口文档 + +## 1. 概述 + +HospitalPay-Go Socket 服务器是一个基于TCP协议的医院支付系统服务器,提供病人入院、出院、消费记录、余额查询等功能。 + +### 1.1 服务器信息 +- **协议**: TCP Socket +- **端口**: 配置文件中指定 +- **编码**: UTF-8 +- **数据格式**: JSON + +### 1.2 消息格式 + +所有请求和响应都遵循以下格式: + +``` +[长度(4位)][功能码(4位)][医院编码(4位)][时间戳(19位)][JSON数据] +``` + +- **长度**: 4位数字,表示整个消息的长度 +- **功能码**: 4位数字,标识请求的功能类型 +- **医院编码**: 4位字符,医院标识码 +- **时间戳**: 19位时间戳,格式为 `yyyy-MM-dd HH:mm:ss` +- **JSON数据**: 具体的请求或响应数据 + +### 1.3 响应格式 + +所有响应都包含以下基础结构: + +```json +{ + "ResultCode": "string", // 结果代码 + "ResultData": object, // 响应数据(可选) + "ResultMsg": "string" // 结果消息(可选) +} +``` + +## 2. 错误码说明 + +| 错误码 | 说明 | +|--------|------| +| 0000 | 成功 | +| 0005 | 未找到病人信息 | +| 0006 | 入院处理失败 | +| 0007 | 病人已入院 | +| 0008 | 系统异常 | +| 0009 | 请求参数错误 | +| 1001 | 出院处理失败 | +| 1002 | 消费额度查询失败 | +| 1003 | 消费记录保存失败 | +| 1004 | 实时余额查询失败 | +| 1005 | 发票同步失败 | + +## 3. 接口详情 + +### 3.1 入院登记 + +**功能码**: `0001` + +**功能说明**: 病人入院时的登记处理 + +**请求参数**: +```json +{ + "FCode": "string" // 病人编号,必填 +} +``` + +**响应参数**: +```json +{ + "ResultCode": "0000", + "ResultData": { + "FCode": "string", // 病人编号 + "FName": "string", // 病人姓名 + "AmountA": 100.00, // A类金额 + "AmountB": 50.00, // B类金额 + "AmountC": 150.00, // C类金额 + "BankAccNo": "string", // 银行账号 + "BankAmount": 1000.00, // 银行余额 + "Fflag": 0, // 状态标志 (0:正常, 1:已入院) + "Flimitflag": 0, // 限制标志 + "Flimitamt": 0.00 // 限制金额 + } +} +``` + +**示例**: +``` +请求: 0001{"FCode":"3516022343"} +响应: {"ResultCode":"0000","ResultData":{"FCode":"3516022343","FName":"测试病人","AmountA":100.00,"AmountB":50.00,"AmountC":150.00,"BankAccNo":"6222021234567890","BankAmount":1000.00,"Fflag":0,"Flimitflag":0,"Flimitamt":0}} +``` + +### 3.2 消费额度查询 + +**功能码**: `0002` + +**功能说明**: 查询病人当月消费额度信息 + +**请求参数**: +```json +{ + "FCode": "string" // 病人编号,必填 +} +``` + +**响应参数**: +```json +{ + "ResultCode": "0000", + "ResultData": { + "AmountA": 50.00, // A类消费金额 + "AmountB": 30.00, // B类消费金额 + "FreeAmountA": 0.00, // A类可用金额 + "FreeAmountB": 0.00, // B类可用金额 + "Checkflag": 0, // 检查标志 + "FCode": "string", // 病人编号 + "FCriminal": "string", // 病人姓名 + "Flag": 0 // 状态标志 + } +} +``` + +### 3.3 出院处理 + +**功能码**: `0003` + +**功能说明**: 病人出院时的处理 + +**请求参数**: +```json +{ + "FCode": "string" // 病人编号,必填 +} +``` + +**响应参数**: +```json +{ + "ResultCode": "0000", + "ResultMsg": "出院处理成功" +} +``` + +### 3.4 消费记录 + +**功能码**: `0004` + +**功能说明**: 记录病人消费信息 + +**请求参数**: +```json +{ + "FCode": "string", // 病人编号,必填 + "InvoiceNo": "string", // 发票号,必填 + "AmountA": 50.00, // A类金额 + "AmountB": 30.00, // B类金额 + "Amount": 80.00, // 总金额 + "FreeAmountA": 0.00, // A类可用金额 + "FreeAmountB": 0.00, // B类可用金额 + "CrtDate": "2024-01-01T10:00:00Z", // 创建日期 + "FCriminal": "string", // 病人姓名 + "CardCode": "string", // 卡号 + "OrderId": 123456 // 订单ID +} +``` + +**响应参数**: +```json +{ + "ResultCode": "0000", + "ResultMsg": "消费记录保存成功" +} +``` + +### 3.5 实时余额查询 + +**功能码**: `0005` + +**功能说明**: 查询病人实时余额信息 + +**请求参数**: +```json +{ + "FCode": "string" // 病人编号,必填 +} +``` + +**响应参数**: 与入院登记响应格式相同 + +### 3.6 发票同步 + +**功能码**: `0006` + +**功能说明**: 同步发票信息到系统 + +**请求参数**: +```json +{ + "InvoiceList": [ + "INV001", + "INV002", + "INV003" + ] +} +``` + +**响应参数**: +```json +{ + "ResultCode": "0000", + "ResultData": [ + { + "BankFlag": 2, // 银行标志 + "CAmount": 100.00, // 金额 + "FCode": "3516022343", // 病人编号 + "Origid": "INV001", // 原始发票号 + "SendDate": "2024-01-01T10:00:00Z" // 发送日期 + } + ] +} +``` + +## 4. 连接管理 + +### 4.1 连接限制 +- 最大并发连接数:配置文件中指定 +- 连接超时时间:配置文件中指定 +- 读取超时时间:配置文件中指定 +- 写入超时时间:配置文件中指定 + +### 4.2 连接流程 +1. 客户端建立TCP连接 +2. 发送请求消息(按照消息格式) +3. 服务器验证医院编码 +4. 处理业务逻辑 +5. 返回响应消息 +6. 关闭连接 + +## 5. 安全说明 + +### 5.1 医院编码验证 +所有请求必须包含正确的医院编码,否则返回"无效的医院编码"错误。 + +### 5.2 超时控制 +- 连接建立后有读取超时限制 +- 响应发送有写入超时限制 +- 业务处理有上下文超时控制(10秒) + +## 6. 监控指标 + +系统提供以下监控指标: +- 活跃连接数 +- 请求计数(按功能码分类) +- 请求处理时间(按功能码分类) +- 错误计数(按功能码和错误码分类) + +## 7. 示例代码 + +### 7.1 Go 客户端示例 + +```go +package main + +import ( + "fmt" + "net" + "time" +) + +func main() { + conn, err := net.Dial("tcp", "localhost:8080") + if err != nil { + panic(err) + } + defer conn.Close() + + // 构造请求消息 + functionCode := "0001" + hospitalCode := "H001" + timestamp := time.Now().Format("2006-01-02 15:04:05") + data := `{"FCode":"3516022343"}` + + message := fmt.Sprintf("%s%s%s%s", functionCode, hospitalCode, timestamp, data) + fullMessage := fmt.Sprintf("%04d%s", len(message), message) + + // 发送请求 + _, err = conn.Write([]byte(fullMessage)) + if err != nil { + panic(err) + } + + // 读取响应 + buffer := make([]byte, 4096) + n, err := conn.Read(buffer) + if err != nil { + panic(err) + } + + response := string(buffer[:n]) + fmt.Printf("Response: %s\n", response) +} +``` + +### 7.2 Python 客户端示例 + +```python +import socket +import json +import time + +def send_request(host, port, function_code, hospital_code, data): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.connect((host, port)) + + # 构造消息 + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + json_data = json.dumps(data) + message = f"{function_code}{hospital_code}{timestamp}{json_data}" + full_message = f"{len(message):04d}{message}" + + # 发送请求 + sock.send(full_message.encode('utf-8')) + + # 接收响应 + response = sock.recv(4096).decode('utf-8') + + # 解析响应 + length = int(response[:4]) + json_response = response[4:4+length] + + return json.loads(json_response) + + finally: + sock.close() + +# 使用示例 +if __name__ == "__main__": + result = send_request( + "localhost", 8080, + "0001", "H001", + {"FCode": "3516022343"} + ) + print(json.dumps(result, indent=2, ensure_ascii=False)) +``` + +## 8. 常见问题 + +### 8.1 连接被拒绝 +- 检查服务器是否启动 +- 检查端口是否正确 +- 检查是否达到最大连接数限制 + +### 8.2 医院编码错误 +- 确认医院编码配置正确 +- 检查请求消息格式是否正确 + +### 8.3 请求超时 +- 检查网络连接 +- 确认服务器负载情况 +- 检查请求数据格式是否正确 + +### 8.4 数据格式错误 +- 确认JSON格式正确 +- 检查必填字段是否完整 +- 验证数据类型是否匹配 + +## 9. 版本历史 + +| 版本 | 日期 | 说明 | +|------|------|------| +| 1.0.0 | 2024-01-01 | 初始版本,支持基础的6个功能接口 | + +## 10. 联系方式 + +如有问题请联系开发团队。 \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..2799dc2 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,105 @@ +# HospitalPay-Go 接口文档 + +欢迎使用 HospitalPay-Go Socket 服务器接口文档。本文档提供了完整的API接口说明、测试用例和快速参考。 + +## 📚 文档目录 + +### 1. [API接口文档](./API接口文档.md) +**完整的接口规范文档** +- 服务器概述和消息格式 +- 详细的接口说明(6个功能接口) +- 错误码说明 +- 连接管理和安全说明 +- 监控指标 +- 客户端示例代码(Go/Python) +- 常见问题解答 + +### 2. [测试用例](./测试用例.md) +**全面的测试用例文档** +- 基础功能测试(每个接口的正常和异常情况) +- 异常情况测试(连接、并发、超时) +- 性能测试(吞吐量、内存、CPU) +- 测试脚本(Go/Python) +- 测试报告模板 + +### 3. [快速参考](./快速参考.md) +**开发者快速查阅手册** +- 消息格式和功能码列表 +- 错误码速查表 +- 数据结构定义 +- 快速示例 +- 客户端代码模板 + +## 🚀 快速开始 + +### 服务器信息 +- **协议**: TCP Socket +- **端口**: 配置文件中指定(默认8080) +- **编码**: UTF-8 +- **数据格式**: JSON + +### 消息格式 +``` +[长度(4位)][功能码(4位)][医院编码(4位)][时间戳(19位)][JSON数据] +``` + +### 支持的功能 +| 功能码 | 功能名称 | 说明 | +|--------|----------|------| +| 0001 | 入院登记 | 病人入院时的登记处理 | +| 0002 | 消费额度查询 | 查询病人当月消费额度 | +| 0003 | 出院处理 | 病人出院时的处理 | +| 0004 | 消费记录 | 记录病人消费信息 | +| 0005 | 实时余额查询 | 查询病人实时余额 | +| 0006 | 发票同步 | 同步发票信息到系统 | + +## 🔧 开发指南 + +### 1. 环境准备 +确保服务器已启动并配置正确的端口和医院编码。 + +### 2. 客户端开发 +参考 [API接口文档](./API接口文档.md) 中的示例代码,或使用 [快速参考](./快速参考.md) 中的代码模板。 + +### 3. 测试验证 +使用 [测试用例](./测试用例.md) 中的测试脚本验证功能是否正常。 + +## 📋 示例请求 + +### 入院登记示例 +``` +请求: 00540001H0012024-01-15 10:30:00{"FCode":"3516022343"} +响应: {"ResultCode":"0000","ResultData":{"FCode":"3516022343","FName":"测试病人",...}} +``` + +### 消费记录示例 +``` +请求: 01840004H0012024-01-15 10:30:00{"FCode":"3516022343","InvoiceNo":"INV001",...} +响应: {"ResultCode":"0000","ResultMsg":"消费记录保存成功"} +``` + +## ⚠️ 重要提醒 + +1. **医院编码验证**: 所有请求必须包含正确的医院编码 +2. **消息格式**: 严格按照指定格式构造消息 +3. **超时控制**: 注意连接和处理超时时间 +4. **错误处理**: 根据错误码进行相应的错误处理 + +## 🐛 问题反馈 + +如果在使用过程中遇到问题: + +1. 首先查阅 [API接口文档](./API接口文档.md) 中的"常见问题"部分 +2. 使用 [测试用例](./测试用例.md) 中的测试脚本进行验证 +3. 检查服务器日志和网络连接 +4. 联系开发团队获取支持 + +## 📖 文档版本 + +| 版本 | 日期 | 说明 | +|------|------|------| +| 1.0.0 | 2024-01-15 | 初始版本,包含6个基础功能接口 | + +--- + +**注意**: 本文档基于当前代码版本生成,如有更新请及时同步文档内容。 \ No newline at end of file diff --git a/docs/快速参考.md b/docs/快速参考.md new file mode 100644 index 0000000..8d1362a --- /dev/null +++ b/docs/快速参考.md @@ -0,0 +1,167 @@ +# HospitalPay-Go Socket 接口快速参考 + +## 消息格式 +``` +[长度(4位)][功能码(4位)][医院编码(4位)][时间戳(19位)][JSON数据] +``` + +## 功能码列表 + +| 功能码 | 功能名称 | 请求参数 | 响应数据 | +|--------|----------|----------|----------| +| 0001 | 入院登记 | `{"FCode":"string"}` | CriminalInfo | +| 0002 | 消费额度查询 | `{"FCode":"string"}` | ConsumeQuota | +| 0003 | 出院处理 | `{"FCode":"string"}` | 成功消息 | +| 0004 | 消费记录 | ConsumeRecord | 成功消息 | +| 0005 | 实时余额查询 | `{"FCode":"string"}` | CriminalInfo | +| 0006 | 发票同步 | `{"InvoiceList":["string"]}` | InvoiceSyncResult[] | + +## 错误码 + +| 错误码 | 说明 | +|--------|------| +| 0000 | 成功 | +| 0005 | 未找到病人信息 | +| 0006 | 入院处理失败 | +| 0007 | 病人已入院 | +| 0008 | 系统异常 | +| 0009 | 请求参数错误 | + +## 数据结构 + +### CriminalInfo (病人信息) +```json +{ + "FCode": "string", // 病人编号 + "FName": "string", // 病人姓名 + "AmountA": 100.00, // A类金额 + "AmountB": 50.00, // B类金额 + "AmountC": 150.00, // C类金额 + "BankAccNo": "string", // 银行账号 + "BankAmount": 1000.00, // 银行余额 + "Fflag": 0, // 状态标志 + "Flimitflag": 0, // 限制标志 + "Flimitamt": 0.00 // 限制金额 +} +``` + +### ConsumeQuota (消费额度) +```json +{ + "AmountA": 50.00, // A类消费金额 + "AmountB": 30.00, // B类消费金额 + "FreeAmountA": 0.00, // A类可用金额 + "FreeAmountB": 0.00, // B类可用金额 + "Checkflag": 0, // 检查标志 + "FCode": "string", // 病人编号 + "FCriminal": "string", // 病人姓名 + "Flag": 0 // 状态标志 +} +``` + +### ConsumeRecord (消费记录) +```json +{ + "FCode": "string", // 病人编号 + "InvoiceNo": "string", // 发票号 + "AmountA": 50.00, // A类金额 + "AmountB": 30.00, // B类金额 + "Amount": 80.00, // 总金额 + "FreeAmountA": 0.00, // A类可用金额 + "FreeAmountB": 0.00, // B类可用金额 + "CrtDate": "2024-01-01T10:00:00Z", // 创建日期 + "FCriminal": "string", // 病人姓名 + "CardCode": "string", // 卡号 + "OrderId": 123456 // 订单ID +} +``` + +### InvoiceSyncResult (发票同步结果) +```json +{ + "BankFlag": 2, // 银行标志 + "CAmount": 100.00, // 金额 + "FCode": "3516022343", // 病人编号 + "Origid": "INV001", // 原始发票号 + "SendDate": "2024-01-01T10:00:00Z" // 发送日期 +} +``` + +## 快速示例 + +### 入院登记 +``` +请求: 00540001H0012024-01-15 10:30:00{"FCode":"3516022343"} +响应: {"ResultCode":"0000","ResultData":{...}} +``` + +### 消费记录 +``` +请求: 01840004H0012024-01-15 10:30:00{"FCode":"3516022343","InvoiceNo":"INV001","AmountA":50.00,"AmountB":30.00,"Amount":80.00,"FreeAmountA":0.00,"FreeAmountB":0.00,"CrtDate":"2024-01-15T10:30:00Z","FCriminal":"测试病人","CardCode":"CARD001","OrderId":123456} +响应: {"ResultCode":"0000","ResultMsg":"消费记录保存成功"} +``` + +### 发票同步 +``` +请求: 00800006H0012024-01-15 10:30:00{"InvoiceList":["INV001","INV002"]} +响应: {"ResultCode":"0000","ResultData":[...]} +``` + +## 客户端代码模板 + +### Go 客户端 +```go +func sendRequest(functionCode, hospitalCode, data string) (string, error) { + conn, err := net.Dial("tcp", "localhost:8080") + if err != nil { + return "", err + } + defer conn.Close() + + timestamp := time.Now().Format("2006-01-02 15:04:05") + message := fmt.Sprintf("%s%s%s%s", functionCode, hospitalCode, timestamp, data) + fullMessage := fmt.Sprintf("%04d%s", len(message), message) + + _, err = conn.Write([]byte(fullMessage)) + if err != nil { + return "", err + } + + buffer := make([]byte, 4096) + n, err := conn.Read(buffer) + if err != nil { + return "", err + } + + return string(buffer[:n]), nil +} +``` + +### Python 客户端 +```python +def send_request(function_code, hospital_code, data): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + sock.connect(('localhost', 8080)) + + timestamp = time.strftime("%Y-%m-%d %H:%M:%S") + json_data = json.dumps(data) + message = f"{function_code}{hospital_code}{timestamp}{json_data}" + full_message = f"{len(message):04d}{message}" + + sock.send(full_message.encode('utf-8')) + response = sock.recv(4096).decode('utf-8') + + length = int(response[:4]) + json_response = response[4:4+length] + return json.loads(json_response) + finally: + sock.close() +``` + +## 常见问题 + +1. **连接被拒绝**: 检查服务器状态和端口 +2. **医院编码错误**: 确认配置文件中的医院编码 +3. **消息格式错误**: 检查长度计算和JSON格式 +4. **超时**: 检查网络连接和服务器负载 \ No newline at end of file diff --git a/docs/测试用例.md b/docs/测试用例.md new file mode 100644 index 0000000..52c2b72 --- /dev/null +++ b/docs/测试用例.md @@ -0,0 +1,622 @@ +# HospitalPay-Go Socket 服务器测试用例 + +## 1. 测试环境准备 + +### 1.1 服务器配置 +- 服务器地址:localhost +- 服务器端口:8080(根据配置文件) +- 医院编码:H001(根据配置文件) + +### 1.2 测试工具 +- TCP客户端工具(如telnet、nc、自定义客户端) +- 网络抓包工具(如Wireshark) + +## 2. 基础功能测试 + +### 2.1 入院登记测试(功能码:0001) + +#### 测试用例 1.1:正常入院登记 +**测试目的**:验证正常病人入院登记功能 + +**请求消息**: +``` +00540001H0012024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0000", + "ResultData": { + "FCode": "3516022343", + "FName": "测试病人", + "AmountA": 100.00, + "AmountB": 50.00, + "AmountC": 150.00, + "BankAccNo": "6222021234567890", + "BankAmount": 1000.00, + "Fflag": 0, + "Flimitflag": 0, + "Flimitamt": 0 + } +} +``` + +#### 测试用例 1.2:病人不存在 +**测试目的**:验证查询不存在的病人 + +**请求消息**: +``` +00540001H0012024-01-15 10:30:00{"FCode":"9999999999"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0005", + "ResultMsg": "未找到病人信息" +} +``` + +#### 测试用例 1.3:病人已入院 +**测试目的**:验证重复入院的处理 + +**请求消息**: +``` +00540001H0012024-01-15 10:30:00{"FCode":"3516022344"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0007", + "ResultMsg": "病人已入院" +} +``` + +#### 测试用例 1.4:请求参数错误 +**测试目的**:验证错误的JSON格式处理 + +**请求消息**: +``` +00540001H0012024-01-15 10:30:00{"FCode":} +``` + +**期望响应**: +```json +{ + "ResultCode": "0009", + "ResultMsg": "请求数据格式错误" +} +``` + +### 2.2 消费额度查询测试(功能码:0002) + +#### 测试用例 2.1:正常消费额度查询 +**测试目的**:验证正常的消费额度查询 + +**请求消息**: +``` +00540002H0012024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0000", + "ResultData": { + "AmountA": 50.00, + "AmountB": 30.00, + "FreeAmountA": 0, + "FreeAmountB": 0, + "Checkflag": 0, + "FCode": "3516022343", + "FCriminal": "测试病人", + "Flag": 0 + } +} +``` + +#### 测试用例 2.2:病人不存在的消费额度查询 +**请求消息**: +``` +00540002H0012024-01-15 10:30:00{"FCode":"9999999999"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0005", + "ResultMsg": "未找到病人信息" +} +``` + +### 2.3 出院处理测试(功能码:0003) + +#### 测试用例 3.1:正常出院处理 +**请求消息**: +``` +00540003H0012024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0000", + "ResultMsg": "出院处理成功" +} +``` + +#### 测试用例 3.2:病人不存在的出院处理 +**请求消息**: +``` +00540003H0012024-01-15 10:30:00{"FCode":"9999999999"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0005", + "ResultMsg": "未找到病人信息" +} +``` + +### 2.4 消费记录测试(功能码:0004) + +#### 测试用例 4.1:正常消费记录 +**请求消息**: +``` +01840004H0012024-01-15 10:30:00{"FCode":"3516022343","InvoiceNo":"INV20240115001","AmountA":50.00,"AmountB":30.00,"Amount":80.00,"FreeAmountA":0.00,"FreeAmountB":0.00,"CrtDate":"2024-01-15T10:30:00Z","FCriminal":"测试病人","CardCode":"CARD001","OrderId":123456} +``` + +**期望响应**: +```json +{ + "ResultCode": "0000", + "ResultMsg": "消费记录保存成功" +} +``` + +#### 测试用例 4.2:缺少必填字段的消费记录 +**请求消息**: +``` +00540004H0012024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0009", + "ResultMsg": "请求数据格式错误" +} +``` + +### 2.5 实时余额查询测试(功能码:0005) + +#### 测试用例 5.1:正常实时余额查询 +**请求消息**: +``` +00540005H0012024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**:与入院登记响应格式相同 + +### 2.6 发票同步测试(功能码:0006) + +#### 测试用例 6.1:正常发票同步 +**请求消息**: +``` +00800006H0012024-01-15 10:30:00{"InvoiceList":["INV001","INV002","INV003"]} +``` + +**期望响应**: +```json +{ + "ResultCode": "0000", + "ResultData": [ + { + "BankFlag": 2, + "CAmount": 100.00, + "FCode": "3516022343", + "Origid": "INV001", + "SendDate": "2024-01-15T10:30:00Z" + }, + { + "BankFlag": 2, + "CAmount": 100.00, + "FCode": "3516022343", + "Origid": "INV002", + "SendDate": "2024-01-15T10:30:00Z" + }, + { + "BankFlag": 2, + "CAmount": 100.00, + "FCode": "3516022343", + "Origid": "INV003", + "SendDate": "2024-01-15T10:30:00Z" + } + ] +} +``` + +#### 测试用例 6.2:空发票列表同步 +**请求消息**: +``` +00540006H0012024-01-15 10:30:00{"InvoiceList":[]} +``` + +**期望响应**: +```json +{ + "ResultCode": "0000", + "ResultData": [] +} +``` + +## 3. 异常情况测试 + +### 3.1 连接测试 + +#### 测试用例 7.1:无效的医院编码 +**请求消息**: +``` +00540001XXXX2024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0009", + "ResultMsg": "无效的医院编码" +} +``` + +#### 测试用例 7.2:无效的功能码 +**请求消息**: +``` +00549999H0012024-01-15 10:30:00{"FCode":"3516022343"} +``` + +**期望响应**: +```json +{ + "ResultCode": "0008", + "ResultMsg": "未知的功能码" +} +``` + +#### 测试用例 7.3:消息长度不足 +**请求消息**: +``` +0001H001 +``` + +**期望行为**:连接被关闭,服务器记录错误日志 + +#### 测试用例 7.4:消息格式错误 +**请求消息**: +``` +INVALID_MESSAGE_FORMAT +``` + +**期望行为**:连接被关闭,服务器记录错误日志 + +### 3.2 并发测试 + +#### 测试用例 8.1:最大连接数测试 +**测试目的**:验证服务器的最大连接数限制 + +**测试步骤**: +1. 同时建立超过配置的最大连接数的连接 +2. 验证超出限制的连接被拒绝 +3. 检查服务器日志记录 + +**期望结果**: +- 在限制内的连接正常处理 +- 超出限制的连接被拒绝 +- 服务器记录相应的警告日志 + +#### 测试用例 8.2:并发请求测试 +**测试目的**:验证服务器处理并发请求的能力 + +**测试步骤**: +1. 同时发送多个不同功能码的请求 +2. 验证所有请求都得到正确响应 +3. 检查响应时间 + +**期望结果**: +- 所有请求都得到正确处理 +- 响应时间在可接受范围内 +- 无数据竞争或死锁 + +### 3.3 超时测试 + +#### 测试用例 9.1:读取超时测试 +**测试步骤**: +1. 建立连接但不发送数据 +2. 等待超过配置的读取超时时间 + +**期望结果**: +- 连接被服务器主动关闭 +- 服务器记录超时日志 + +#### 测试用例 9.2:写入超时测试 +**测试步骤**: +1. 发送请求后立即关闭客户端的接收 +2. 服务器尝试发送响应 + +**期望结果**: +- 服务器检测到写入超时 +- 连接被正确清理 + +## 4. 性能测试 + +### 4.1 吞吐量测试 + +#### 测试用例 10.1:单连接吞吐量 +**测试目的**:测试单个连接的处理能力 + +**测试方法**: +- 使用单个连接连续发送1000个请求 +- 记录总处理时间和平均响应时间 + +**性能指标**: +- 每秒处理请求数(TPS) +- 平均响应时间 +- 95%响应时间 + +#### 测试用例 10.2:多连接吞吐量 +**测试目的**:测试多连接并发处理能力 + +**测试方法**: +- 使用10个并发连接,每个连接发送100个请求 +- 记录总处理时间和响应时间分布 + +### 4.2 内存和CPU使用率测试 + +#### 测试用例 11.1:长时间运行测试 +**测试目的**:验证服务器长时间运行的稳定性 + +**测试方法**: +- 持续发送请求24小时 +- 监控内存使用率、CPU使用率 +- 检查是否有内存泄漏 + +## 5. 测试脚本 + +### 5.1 Go 测试脚本 + +```go +package main + +import ( + "fmt" + "net" + "time" + "sync" + "log" +) + +func testConnection(testCase string, message string, expectedCode string) { + conn, err := net.Dial("tcp", "localhost:8080") + if err != nil { + log.Printf("测试用例 %s 失败: 连接错误 %v", testCase, err) + return + } + defer conn.Close() + + // 发送请求 + _, err = conn.Write([]byte(message)) + if err != nil { + log.Printf("测试用例 %s 失败: 发送错误 %v", testCase, err) + return + } + + // 读取响应 + buffer := make([]byte, 4096) + conn.SetReadDeadline(time.Now().Add(5 * time.Second)) + n, err := conn.Read(buffer) + if err != nil { + log.Printf("测试用例 %s 失败: 读取错误 %v", testCase, err) + return + } + + response := string(buffer[:n]) + log.Printf("测试用例 %s: 响应 %s", testCase, response) + + // 简单验证响应码 + if len(response) > 4 { + responseData := response[4:] + if expectedCode != "" && !contains(responseData, expectedCode) { + log.Printf("测试用例 %s 失败: 期望响应码 %s", testCase, expectedCode) + } else { + log.Printf("测试用例 %s 成功", testCase) + } + } +} + +func contains(s, substr string) bool { + return len(s) >= len(substr) && s[:len(substr)] == substr +} + +func main() { + // 测试用例 + testCases := []struct { + name string + message string + expected string + }{ + { + "1.1-正常入院登记", + "00540001H0012024-01-15 10:30:00{\"FCode\":\"3516022343\"}", + "\"ResultCode\":\"0000\"", + }, + { + "1.2-病人不存在", + "00540001H0012024-01-15 10:30:00{\"FCode\":\"9999999999\"}", + "\"ResultCode\":\"0005\"", + }, + { + "7.1-无效医院编码", + "00540001XXXX2024-01-15 10:30:00{\"FCode\":\"3516022343\"}", + "\"ResultCode\":\"0009\"", + }, + { + "7.2-无效功能码", + "00549999H0012024-01-15 10:30:00{\"FCode\":\"3516022343\"}", + "\"ResultCode\":\"0008\"", + }, + } + + for _, tc := range testCases { + testConnection(tc.name, tc.message, tc.expected) + time.Sleep(100 * time.Millisecond) // 避免过快请求 + } + + // 并发测试 + log.Println("开始并发测试...") + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + testConnection( + fmt.Sprintf("并发测试-%d", id), + "00540001H0012024-01-15 10:30:00{\"FCode\":\"3516022343\"}", + "\"ResultCode\":\"0000\"", + ) + }(i) + } + wg.Wait() + log.Println("并发测试完成") +} +``` + +### 5.2 Python 测试脚本 + +```python +import socket +import json +import time +import threading +from concurrent.futures import ThreadPoolExecutor + +def send_request(test_name, message, expected_code=None): + """发送测试请求""" + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(5) + sock.connect(('localhost', 8080)) + + # 发送请求 + sock.send(message.encode('utf-8')) + + # 接收响应 + response = sock.recv(4096).decode('utf-8') + + print(f"测试用例 {test_name}: 响应 {response}") + + # 验证响应码 + if expected_code and len(response) > 4: + response_data = response[4:] + if expected_code in response_data: + print(f"测试用例 {test_name} 成功") + else: + print(f"测试用例 {test_name} 失败: 期望响应码 {expected_code}") + + sock.close() + return True + + except Exception as e: + print(f"测试用例 {test_name} 失败: {e}") + return False + +def run_basic_tests(): + """运行基础功能测试""" + test_cases = [ + { + 'name': '1.1-正常入院登记', + 'message': '00540001H0012024-01-15 10:30:00{"FCode":"3516022343"}', + 'expected': '"ResultCode":"0000"' + }, + { + 'name': '1.2-病人不存在', + 'message': '00540001H0012024-01-15 10:30:00{"FCode":"9999999999"}', + 'expected': '"ResultCode":"0005"' + }, + { + 'name': '2.1-正常消费额度查询', + 'message': '00540002H0012024-01-15 10:30:00{"FCode":"3516022343"}', + 'expected': '"ResultCode":"0000"' + }, + { + 'name': '7.1-无效医院编码', + 'message': '00540001XXXX2024-01-15 10:30:00{"FCode":"3516022343"}', + 'expected': '"ResultCode":"0009"' + }, + ] + + for test_case in test_cases: + send_request(test_case['name'], test_case['message'], test_case['expected']) + time.sleep(0.1) # 避免过快请求 + +def run_concurrent_tests(): + """运行并发测试""" + print("开始并发测试...") + + def concurrent_request(thread_id): + return send_request( + f'并发测试-{thread_id}', + '00540001H0012024-01-15 10:30:00{"FCode":"3516022343"}', + '"ResultCode":"0000"' + ) + + with ThreadPoolExecutor(max_workers=10) as executor: + futures = [executor.submit(concurrent_request, i) for i in range(10)] + results = [future.result() for future in futures] + + success_count = sum(results) + print(f"并发测试完成: {success_count}/10 成功") + +if __name__ == "__main__": + print("开始基础功能测试...") + run_basic_tests() + + print("\n开始并发测试...") + run_concurrent_tests() + + print("\n所有测试完成") +``` + +## 6. 测试报告模板 + +### 6.1 测试执行记录 + +| 测试用例 | 执行时间 | 执行结果 | 响应时间 | 备注 | +|----------|----------|----------|----------|------| +| 1.1-正常入院登记 | 2024-01-15 10:30:00 | 通过 | 50ms | - | +| 1.2-病人不存在 | 2024-01-15 10:30:05 | 通过 | 45ms | - | +| 7.1-无效医院编码 | 2024-01-15 10:30:10 | 通过 | 30ms | - | + +### 6.2 性能测试结果 + +| 测试项目 | 测试结果 | 标准值 | 是否通过 | +|----------|----------|--------|----------| +| 单连接TPS | 1000 req/s | >500 req/s | 通过 | +| 平均响应时间 | 50ms | <100ms | 通过 | +| 95%响应时间 | 80ms | <200ms | 通过 | +| 最大并发连接 | 100 | 100 | 通过 | + +### 6.3 问题记录 + +| 问题编号 | 问题描述 | 严重程度 | 状态 | 备注 | +|----------|----------|----------|------|------| +| BUG-001 | 某种情况下响应超时 | 中 | 已修复 | - | + +## 7. 测试环境清理 + +测试完成后需要: +1. 清理测试数据 +2. 重置数据库状态 +3. 检查服务器日志 +4. 验证系统资源使用情况 \ No newline at end of file