本项目包含完整的测试套件,涵盖服务端单元测试、安全回归测试、压力测试和前端单元测试、E2E 测试。
hanphone-blog/
├── server/ # Java Spring Boot 后端
│ ├── test.py # 安全 & 功能回归测试 (39 用例)
│ ├── stress_test.py # 压力测试 (渐进式/固定/尖峰)
│ └── src/test/java/com/example/blog/
│ ├── BlogApplicationTests.java # 应用上下文测试
│ ├── util/ # 工具类测试
│ │ ├── BcryptUtilsTest.java
│ │ └── MarkdownUtilsTest.java
│ ├── po/ # 实体类测试
│ │ └── ResultTest.java
│ └── constants/ # 常量类测试
│ └── ConstantsTest.java
│
└── web/ # Next.js 前端
├── src/
│ ├── test/
│ │ └── setup.ts # 测试环境配置
│ ├── lib/__tests__/
│ │ └── utils.test.ts # 工具函数测试
│ └── components/__tests__/
│ └── Button.test.tsx # 组件测试
│
└── e2e/ # E2E 测试(暂未配置)
└── admin-file/ # 文件服务 (Express.js)
└── server.js # 主服务(目前未配置独立测试套件)
cd server
# 运行所有测试
mvn test
# 运行单个测试类
mvn test -Dtest=BcryptUtilsTest
# 生成测试报告
mvn surefire-report:report
针对已部署服务的黑盒测试,覆盖安全响应头、输入防御、并发、认证鉴权、XSS、密码策略、验证码限流、SQL 注入、CORS、HTTP 方法安全、评论功能、Actuator 端点等 12 个测试组。
cd server
# 安装依赖
pip install requests
# 运行全量测试(默认目标 https://hanphone.cn/api)
python3 test.py
# 指定目标服务器
python3 test.py --base-url http://localhost:8090/api
# 跳过 T11 评论测试(CommentController 修复未部署时)
python3 test.py --skip-t11
支持三种策略:渐进式加压 (ramp-up)、固定并发 (fixed)、尖峰冲击 (spike)。
cd server
# 渐进式加压:从 1 并发逐步增加到 200,找到性能拐点(默认)
python3 stress_test.py
# 固定 50 并发,持续 60 秒
python3 stress_test.py --concurrency 50 --duration 60
# 尖峰测试:200 并发冲击 10 秒
python3 stress_test.py --spike
# 指定测试接口
python3 stress_test.py --endpoints /blogs,/search
输出指标:RPS、延迟 (avg/P50/P95/P99/max/stdev)、成功率、状态码分布、性能拐点分析与建议。
由于项目采用了 pnpm workspace,推荐在根目录运行测试:
# 安装全量依赖
pnpm install
# 运行 Web 单元测试
pnpm --filter web test
# 运行 Web 单元测试(监视模式)
pnpm --filter web test:watch
# 生成覆盖率报告
pnpm --filter web test:coverage
目前 admin-file 模块暂未配置独立的测试框架。需要时可引入 Jest 或 Vitest 并编写接口测试:
cd admin-file
# 手动启动服务进行接口验证
pnpm start
# 使用 curl 测试接口
curl -X POST http://localhost:4000/upload/avatar \
-F "avatar=@test-avatar.png"
本项目使用 GitHub Actions 进行持续集成,配置位于 .github/workflows/ci.yml。
每次推送或 PR 到 main 分支时,会自动运行:
{被测类名}Test@DisplayName 描述测试目的@testing-library/reactnext/navigation, next/image)__tests__ 目录或命名为 *.test.tspackage com.example.blog.service;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import static org.junit.jupiter.api.Assertions.*;
class UserServiceTest {
@Test
@DisplayName("测试用户注册")
void register_ShouldCreateNewUser() {
// Arrange
UserService service = new UserService();
// Act
User user = service.register("test@example.com", "password");
// Assert
assertNotNull(user);
assertEquals("test@example.com", user.getEmail());
}
}
// src/components/__tests__/MyComponent.test.tsx
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { MyComponent } from '../MyComponent'
describe('MyComponent', () => {
it('应该正确渲染', () => {
render(<MyComponent title="测试标题" />)
expect(screen.getByText('测试标题')).toBeInTheDocument()
})
})
// e2e/my-feature.spec.ts
import { test, expect } from '@playwright/test'
test.describe('我的功能', () => {
test('应该正常工作', async ({ page }) => {
await page.goto('/my-feature')
await expect(page.locator('h1')).toHaveText('我的功能')
})
})
查看覆盖率报告:
server/target/site/jacoco/index.htmlweb/coverage/index.html在 IDE 中右键点击测试方法选择 “Debug”,或添加断点运行:
mvn test -Dmaven.surefire.debug
# Vitest UI 模式
pnpm vitest --ui
# Playwright 调试模式(如有配置)
pnpm exec playwright test --debug