本文目录导读:

- Python + requests + JSON Schema
- Postman + Newman (使用集合批量测试)
- 使用 YAML 配置文件的通用校验脚本
- 使用 pytest + pytest-xdist 并行测试
- 使用 Jenkins Pipeline 自动化
- 推荐使用方案
Python + requests + JSON Schema
import requests
import json
from jsonschema import validate, ValidationError
import pandas as pd
from typing import Dict, List
class APIParameterValidator:
def __init__(self, base_url: str):
self.base_url = base_url
def generate_test_cases(self, api_spec: Dict) -> List[Dict]:
"""
根据API规范生成测试用例
"""
test_cases = []
# 必填参数测试
for param, spec in api_spec.get('required_params', {}).items():
test_cases.append({
'name': f'缺少必填参数: {param}',
'params': {k: v for k, v in api_spec.get('default_params', {}).items()
if k != param},
'expected_status': 400
})
# 参数类型测试
for param, spec in api_spec.get('params', {}).items():
if spec.get('type') == 'integer':
test_cases.append({
'name': f'参数类型错误: {param}',
'params': {**api_spec.get('default_params', {}),
param: 'not_a_number'},
'expected_status': 400
})
# 边界值测试
for param, spec in api_spec.get('params', {}).items():
if 'min' in spec and 'max' in spec:
test_cases.extend([
{
'name': f'参数小于最小值: {param}',
'params': {**api_spec.get('default_params', {}),
param: spec['min'] - 1},
'expected_status': 400
},
{
'name': f'参数大于最大值: {param}',
'params': {**api_spec.get('default_params', {}),
param: spec['max'] + 1},
'expected_status': 400
}
])
return test_cases
def validate_response(self, response: requests.Response,
expected_status: int) -> Dict:
"""验证响应"""
result = {
'status': 'pass' if response.status_code == expected_status else 'fail',
'status_code': response.status_code,
'expected_status': expected_status,
'response_time': response.elapsed.total_seconds(),
'body': response.text[:500] if response.text else ''
}
return result
def run_batch_tests(self, endpoint: str, api_spec: Dict) -> pd.DataFrame:
"""批量运行测试"""
test_cases = self.generate_test_cases(api_spec)
results = []
for test_case in test_cases:
try:
response = requests.post(
f"{self.base_url}{endpoint}",
params=test_case['params'],
timeout=10
)
result = self.validate_response(response,
test_case['expected_status'])
result['test_name'] = test_case['name']
result['params'] = test_case['params']
results.append(result)
except Exception as e:
results.append({
'test_name': test_case['name'],
'status': 'error',
'error': str(e),
'params': test_case['params']
})
return pd.DataFrame(results)
# 使用示例
if __name__ == "__main__":
# API规范定义
api_spec = {
'endpoint': '/api/user/create',
'method': 'POST',
'required_params': ['username', 'email', 'age'],
'default_params': {
'username': 'test_user',
'email': 'test@example.com',
'age': 25
},
'params': {
'username': {
'type': 'string',
'min_length': 3,
'max_length': 50
},
'email': {
'type': 'string',
'pattern': r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
},
'age': {
'type': 'integer',
'min': 0,
'max': 150
}
}
}
validator = APIParameterValidator('https://api.example.com')
results = validator.run_batch_tests('/api/user/create', api_spec)
print(results)
results.to_csv('api_test_results.csv', index=False)
Postman + Newman (使用集合批量测试)
// postman_collection.json 示例
{
"info": {
"name": "API参数校验测试",
"description": "批量验证接口参数"
},
"item": [
{
"name": "必填参数测试",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('状态码检查', function() {",
" pm.response.to.have.status(400);",
"});",
"",
"pm.test('错误信息检查', function() {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('error');",
"});"
]
}
}
],
"request": {
"method": "POST",
"header": [
{"key": "Content-Type", "value": "application/json"}
],
"body": {
"mode": "raw",
"raw": "{\"email\": \"test@example.com\"}"
},
"url": {
"raw": "{{base_url}}/api/user/create",
"host": ["{{base_url}}"],
"path": ["api", "user", "create"]
}
}
}
]
}
使用 YAML 配置文件的通用校验脚本
import yaml
import requests
import json
import re
from typing import Dict, List, Any
from dataclasses import dataclass
from datetime import datetime
@dataclass
class ValidationRule:
field: str
required: bool = False
type: str = 'string'
min_length: int = None
max_length: int = None
pattern: str = None
enum: List[str] = None
min_value: float = None
max_value: float = None
class ParameterValidator:
def __init__(self, config_path: str):
with open(config_path, 'r', encoding='utf-8') as f:
self.config = yaml.safe_load(f)
self.results = []
def validate_parameter(self, value: Any, rule: ValidationRule) -> bool:
"""验证单个参数"""
if rule.required and value is None:
return False
if value is not None:
# 类型检查
if rule.type == 'string' and not isinstance(value, str):
return False
elif rule.type == 'integer' and not isinstance(value, int):
return False
elif rule.type == 'float' and not isinstance(value, (int, float)):
return False
elif rule.type == 'boolean' and not isinstance(value, bool):
return False
# 字符串长度检查
if rule.type == 'string':
if rule.min_length and len(value) < rule.min_length:
return False
if rule.max_length and len(value) > rule.max_length:
return False
# 正则表达式检查
if rule.pattern and not re.match(rule.pattern, value):
return False
# 数值范围检查
if rule.type in ['integer', 'float']:
if rule.min_value is not None and value < rule.min_value:
return False
if rule.max_value is not None and value > rule.max_value:
return False
# 枚举值检查
if rule.enum and value not in rule.enum:
return False
return True
def generate_test_data(self, rules: List[ValidationRule]) -> List[Dict]:
"""生成测试数据"""
test_cases = []
# 正常测试数据
normal_data = {}
for rule in rules:
if rule.type == 'string':
normal_data[rule.field] = 'test_string'
elif rule.type == 'integer':
normal_data[rule.field] = 100
elif rule.type == 'float':
normal_data[rule.field] = 100.5
elif rule.type == 'boolean':
normal_data[rule.field] = True
test_cases.append({
'name': '正常参数测试',
'data': normal_data,
'expect_pass': True
})
# 异常测试数据
for rule in rules:
if rule.required:
# 缺少必填参数
missing_data = {k: v for k, v in normal_data.items()
if k != rule.field}
test_cases.append({
'name': f'缺少必填参数: {rule.field}',
'data': missing_data,
'expect_pass': False
})
# 类型错误
if rule.type == 'integer':
wrong_data = normal_data.copy()
wrong_data[rule.field] = 'not_a_number'
test_cases.append({
'name': f'参数类型错误: {rule.field}',
'data': wrong_data,
'expect_pass': False
})
return test_cases
def run_validation(self, config_key: str = None):
"""运行验证"""
apis = self.config.get('apis', [])
if config_key:
apis = [api for api in apis if api['name'] == config_key]
for api in apis:
print(f"\n=== 验证API: {api['name']} ===")
# 解析规则
rules = []
for field_config in api.get('parameters', []):
rule = ValidationRule(
field=field_config['name'],
required=field_config.get('required', False),
type=field_config.get('type', 'string'),
min_length=field_config.get('min_length'),
max_length=field_config.get('max_length'),
pattern=field_config.get('pattern'),
enum=field_config.get('enum'),
min_value=field_config.get('min_value'),
max_value=field_config.get('max_value')
)
rules.append(rule)
# 生成测试数据并验证
test_cases = self.generate_test_data(rules)
for test in test_cases:
is_valid = all(
self.validate_parameter(
test['data'].get(rule.field), rule
)
for rule in rules
)
status = 'PASS' if is_valid == test['expect_pass'] else 'FAIL'
print(f"{status}: {test['name']}")
self.results.append({
'api': api['name'],
'test': test['name'],
'status': status,
'timestamp': datetime.now().isoformat()
})
def generate_report(self, output_path: str = 'validation_report.json'):
"""生成报告"""
report = {
'total_tests': len(self.results),
'passed_tests': len([r for r in self.results if r['status'] == 'PASS']),
'failed_tests': len([r for r in self.results if r['status'] == 'FAIL']),
'results': self.results
}
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(f"\n报告已生成: {output_path}")
print(f"总计: {report['total_tests']} | 通过: {report['passed_tests']} | 失败: {report['failed_tests']}")
# YAML配置文件示例
"""
apis:
- name: user_create
endpoint: /api/user/create
method: POST
parameters:
- name: username
required: true
type: string
min_length: 3
max_length: 50
- name: email
required: true
type: string
pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
- name: age
required: true
type: integer
min_value: 0
max_value: 150
- name: gender
type: string
enum: ['male', 'female', 'other']
"""
# 使用示例
if __name__ == "__main__":
validator = ParameterValidator('api_config.yaml')
validator.run_validation()
validator.generate_report()
使用 pytest + pytest-xdist 并行测试
import pytest
import requests
from typing import Dict, List
from dataclasses import dataclass
@dataclass
class TestCase:
name: str
params: Dict
expected_status: int
expected_response: Dict = None
class APITestGenerator:
def __init__(self, base_url: str):
self.base_url = base_url
@pytest.fixture(autouse=True)
def setup(self):
self.session = requests.Session()
yield
self.session.close()
def generate_params_test(self, api_spec: Dict) -> List[TestCase]:
"""生成参数测试用例"""
test_cases = []
# 各种参数组合测试
param_combinations = []
# 正常参数
param_combinations.append({
'name': '正常参数',
'params': api_spec.get('valid_params', {}),
'expected_status': 200
})
# 空参数
param_combinations.append({
'name': '空参数',
'params': {},
'expected_status': 400
})
# 无效参数
param_combinations.append({
'name': '无效参数',
'params': {'invalid_param': 'value'},
'expected_status': 400
})
for combo in param_combinations:
test_cases.append(TestCase(**combo))
return test_cases
# 测试类
class TestAPIEndpoint:
@pytest.mark.parametrize("test_case", [
TestCase(name="测试用例1", params={"key": "value"},
expected_status=200),
TestCase(name="测试用例2", params={},
expected_status=400),
])
def test_api_endpoint(self, test_case):
response = requests.post(
"https://api.example.com/endpoint",
params=test_case.params
)
assert response.status_code == test_case.expected_status
# 运行命令
# pytest test_api.py -v -n auto # 并行运行
# pytest test_api.py --html=report.html # 生成HTML报告
使用 Jenkins Pipeline 自动化
pipeline {
agent any
parameters {
string(name: 'API_CONFIG', defaultValue: 'api_config.yaml',
description: 'API配置文件路径')
choice(name: 'ENVIRONMENT', choices: ['dev', 'staging', 'prod'],
description: '测试环境')
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Validate Config') {
steps {
sh 'python validate_config.py ${API_CONFIG}'
}
}
stage('Run API Tests') {
parallel {
stage('Parameter Validation') {
steps {
sh 'python parameter_validator.py --config ${API_CONFIG}'
}
}
stage('Response Validation') {
steps {
sh 'python response_validator.py --config ${API_CONFIG}'
}
}
}
}
stage('Generate Report') {
steps {
sh 'python generate_report.py'
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'reports',
reportFiles: 'index.html',
reportName: 'API Validation Report'
])
}
}
}
post {
always {
junit 'reports/*.xml'
cleanWs()
}
}
}
推荐使用方案
- 快速原型/小项目:使用 Postman + Newman
- 复杂项目/CI集成:使用 Python + pytest
- 企业级应用:使用 Jenkins Pipeline + pytest
- API文档驱动:使用 OpenAPI/Swagger 自动生成测试
需要我详细解释某个方案的具体实现,或者帮你针对特定场景选择最合适的方案吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播