HospitalPay-Go/docs/测试用例.md

622 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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. 验证系统资源使用情况