以下是基于Django框架开发Web测试平台的详细实现方案,包含核心功能模块和关键技术实现:
---
### **1. 项目结构规划**
```bash
test_platform/
├── apps/
│ ├── testcase/ # 测试用例管理
│ ├── testenv/ # 测试环境管理
│ ├── reports/ # 测试报告系统
│ └── execution/ # 测试执行引擎
├── core/ # 核心功能
│ ├── runners/ # 测试执行器
│ │ ├── api_runner.py
│ │ ├── web_runner.py
│ │ └── performance_runner.py
│ └── utils/ # 通用工具
├── config/ # 项目配置
├── static/ # 静态资源
├── templates/ # 模板文件
└── requirements.txt # 依赖文件
```
---
### **2. 核心模型设计(models.py)**
```python
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class TestCase(models.Model):
CASE_TYPE_CHOICES = [
('API', '接口测试'),
('WEB', 'Web UI测试'),
('PERF', '性能测试'),
]
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
case_type = models.CharField(max_length=20, choices=CASE_TYPE_CHOICES)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
script_content = models.TextField(blank=True)
config = models.JSONField(default=dict) # 测试配置存储
def __str__(self):
return f"{self.get_case_type_display()} - {self.name}"
class TestExecution(models.Model):
STATUS_CHOICES = [
('PENDING', '待执行'),
('RUNNING', '执行中'),
('PASSED', '通过'),
('FAILED', '失败'),
('ERROR', '错误'),
]
test_case = models.ForeignKey(TestCase, on_delete=models.CASCADE)
start_time = models.DateTimeField()
end_time = models.DateTimeField(null=True)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='PENDING')
result_data = models.JSONField(default=dict)
logs = models.TextField(blank=True)
executed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
@property
def duration(self):
if self.end_time and self.start_time:
return self.end_time - self.start_time
return None
```
---
### **3. 测试执行引擎实现**
#### **API测试执行器示例(runners/api_runner.py)**
```python
import requests
import json
from django.utils import timezone
class APITestRunner:
def __init__(self, test_case):
self.test_case = test_case
self.config = test_case.config
self.result = {
'status': 'PENDING',
'assertions': [],
'response': None,
'errors': []
}
def execute(self):
try:
# 执行请求
response = requests.request(
method=self.config.get('method', 'GET'),
url=self.config['url'],
headers=self.config.get('headers', {}),
json=self.config.get('body', {}),
timeout=30
)
# 记录响应
self.result['response'] = {
'status_code': response.status_code,
'headers': dict(response.headers),
'body': response.json() if response.content else None
}
# 执行断言
for assertion in self.config.get('assertions', []):
self._execute_assertion(assertion)
self.result['status'] = 'PASSED' if all(
a['success'] for a in self.result['assertions']
) else 'FAILED'
except Exception as e:
self.result['status'] = 'ERROR'
self.result['errors'].append(str(e))
return self.result
def _execute_assertion(self, assertion):
# 实现各种断言逻辑
assertion_result = {
'name': assertion['name'],
'type': assertion['type'],
'success': False
}
try:
if assertion['type'] == 'status_code':
assertion_result['success'] = (
self.result['response']['status_code'] == assertion['expected']
)
elif assertion['type'] == 'json_path':
# 使用jsonpath实现
pass
self.result['assertions'].append(assertion_result)
except Exception as e:
self.result['errors'].append(f"Assertion error: {str(e)}")
```
---
### **4. 视图层实现(views.py)**
```python
from django.views import View
from django.http import JsonResponse
from .models import TestCase, TestExecution
from .runners import get_runner_for_case
class ExecuteTestCaseView(View):
def post(self, request, case_id):
try:
test_case = TestCase.objects.get(id=case_id)
execution = TestExecution.objects.create(
test_case=test_case,
executed_by=request.user,
start_time=timezone.now()
)
# 获取对应的执行器
runner_class = get_runner_for_case(test_case.case_type)
runner = runner_class(test_case)
result = runner.execute()
# 更新执行结果
execution.end_time = timezone.now()
execution.status = result['status']
execution.result_data = result
execution.save()
return JsonResponse({
'status': 'success',
'execution_id': execution.id
})
except TestCase.DoesNotExist:
return JsonResponse({'error': 'Test case not found'}, status=404)
class TestReportView(View):
def get(self, request, execution_id):
execution = TestExecution.objects.get(id=execution_id)
return JsonResponse({
'status': execution.status,
'duration': execution.duration.total_seconds() if execution.duration else None,
'assertions': execution.result_data.get('assertions', []),
'errors': execution.result_data.get('errors', [])
})
```
---
### **5. URL路由配置(urls.py)**
```python
from django.urls import path
from . import views
urlpatterns = [
path('api/testcases/', views.TestCaseListView.as_view(), name='testcase-list'),
path('api/testcases/
path('api/execute/
path('api/reports/
]
```
---
### **6. 前端模板示例(templates/dashboard.html)**
```html
{% extends "base.html" %}
{% block content %}
测试平台仪表盘
// AJAX执行测试用例
document.querySelectorAll('.btn-run').forEach(btn => {
btn.addEventListener('click', async () => {
const caseId = btn.dataset.caseId;
const response = await fetch(`/api/execute/${caseId}/`, {
method: 'POST',
headers: {
'X-CSRFToken': '{{ csrf_token }}',
'Content-Type': 'application/json'
}
});
const result = await response.json();
if (result.status === 'success') {
window.location.href = `/reports/${result.execution_id}/`;
}
});
});
{% endblock %}
```
---
### **7. 高级功能扩展**
#### **7.1 异步任务执行(Celery集成)**
```python
# tasks.py
from celery import shared_task
from .models import TestExecution
@shared_task
def async_execute_test_case(execution_id):
execution = TestExecution.objects.get(id=execution_id)
execution.status = 'RUNNING'
execution.save()
try:
runner_class = get_runner_for_case(execution.test_case.case_type)
runner = runner_class(execution.test_case)
result = runner.execute()
execution.end_time = timezone.now()
execution.status = result['status']
execution.result_data = result
execution.save()
except Exception as e:
execution.status = 'ERROR'
execution.result_data = {'error': str(e)}
execution.save()
```
---
#### **7.2 测试环境管理**
```python
# models.py
class TestEnvironment(models.Model):
ENV_TYPES = [
('DEV', '开发环境'),
('TEST', '测试环境'),
('PROD', '生产环境'),
]
name = models.CharField(max_length=100)
env_type = models.CharField(max_length=20, choices=ENV_TYPES)
base_url = models.URLField()
config = models.JSONField(default=dict)
is_active = models.BooleanField(default=True)
class EnvironmentVariable(models.Model):
environment = models.ForeignKey(TestEnvironment, on_delete=models.CASCADE)
key = models.CharField(max_length=100)
value = models.CharField(max_length=500)
is_secret = models.BooleanField(default=False)
```
---
#### **7.3 性能测试集成(Locust)**
```python
# runners/performance_runner.py
import subprocess
from pathlib import Path
from django.conf import settings
class PerformanceTestRunner:
def __init__(self, test_case):
self.test_case = test_case
self.locustfile = self._generate_locustfile()
def _generate_locustfile(self):
locust_template = f'''
from locust import HttpUser, task
class PerformanceTestUser(HttpUser):
@task
def {self.test_case.config.get('endpoint')}:
self.client.get("{self.test_case.config.get('path')}")
'''
file_path = Path(settings.MEDIA_ROOT) / f'locust_files/{self.test_case.id}.py'
file_path.write_text(locust_template)
return file_path
def execute(self):
cmd = [
'locust',
'-f', str(self.locustfile),
'--headless',
'-u', str(self.test_case.config.get('users', 100)),
'-r', str(self.test_case.config.get('spawn_rate', 10)),
'-t', f"{self.test_case.config.get('duration', 1)}m",
'--csv', f'results/{self.test_case.id}'
]
process = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
return {
'output': process.stdout,
'error': process.stderr,
'returncode': process.returncode
}
```
---
### **8. 安全增强措施**
1. **参数校验装饰器**:
```python
def validate_testcase_config(view_func):
def wrapper(request, *args, **kwargs):
config = request.POST.get('config', {})
try:
# 验证配置有效性
if not isinstance(config, dict):
raise ValidationError("Invalid configuration format")
# 添加具体校验逻辑
return view_func(request, *args, **kwargs)
except ValidationError as e:
return JsonResponse({'error': str(e)}, status=400)
return wrapper
```
2. **权限控制**:
```python
from django.contrib.auth.mixins import PermissionRequiredMixin
class TestCaseCreateView(PermissionRequiredMixin, CreateView):
permission_required = 'testcase.add_testcase'
model = TestCase
fields = ['name', 'description', 'case_type', 'script_content']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super().form_valid(form)
```
---
### **9. 部署配置示例(Docker)**
```dockerfile
# Dockerfile
FROM python:3.10-slim
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
WORKDIR /app
RUN apt-get update && apt-get install -y \
gcc \
python3-dev \
default-jre-headless # 如需Java支持
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "config.wsgi"]
```
---
### **10. 关键依赖清单(requirements.txt)**
```text
Django==4.2
celery==5.3.1
requests==2.31.0
python-dotenv==1.0.0
locust==2.15.1
selenium==4.10.0
pytest==7.4.0
```
---
### **平台扩展方向**
1. **测试类型支持**:
- API测试(Postman/Swagger集成)
- Web UI测试(Selenium/Playwright)
- 移动端测试(Appium)
- 性能测试(Locust/JMeter)
- 安全测试(OWASP ZAP集成)
2. **CI/CD集成**:
- Jenkins Pipeline支持
- GitLab CI配置生成
- GitHub Actions集成
3. **智能测试**:
- 基于历史数据的智能用例生成
- 缺陷预测模型
- 自动修复建议
4. **分布式执行**:
- Kubernetes任务调度
- 多节点负载均衡
- 云端执行器管理
---
该方案为构建企业级测试平台提供了完整的Django实现框架,可根据实际需求进行模块化扩展和定制开发。建议从基础功能开始迭代开发,逐步添加复杂功能模块。