mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-29 18:23:59 +08:00
112 lines
3.9 KiB
Markdown
112 lines
3.9 KiB
Markdown
# 单元测试指南
|
||||
|
|
|
|||
|
|
本目录包含 xiaozhi 测试页面模块的单元测试。
|
|||
|
|
|
|||
|
|
## 摘要
|
|||
|
|
|
|||
|
|
- **测试总数:** 13 个单元测试
|
|||
|
|
- **测试文件:** 2 个浏览器兼容的测试文件
|
|||
|
|
- **测试运行器:** 基于浏览器(无需 npm)
|
|||
|
|
- **测试覆盖:** 麦克风检测、HTTP 检测、Live2D 动作、错误处理
|
|||
|
|
|
|||
|
|
## 测试文件
|
|||
|
|
|
|||
|
|
- `js/core/audio/recorder.test.browser.js` - 浏览器兼容的麦克风可用性检测和 HTTP 非本地访问检测测试
|
|||
|
|
- `js/core/mcp/tools.test.browser.js` - 浏览器兼容的 MCP 工具和 Live2D 动作执行测试
|
|||
|
|
|
|||
|
|
**注意:** `.browser.js` 版本无需任何 npm 依赖。它们使用内置在 `test-runner.html` 中的简单测试框架。
|
|||
|
|
|
|||
|
|
## 运行测试
|
|||
|
|
|
|||
|
|
### 基于浏览器的测试运行器(无需 npm!)
|
|||
|
|
|
|||
|
|
1. 启动本地服务器:
|
|||
|
|
```bash
|
|||
|
|
cd main/xiaozhi-server/test
|
|||
|
|
python -m http.server 8007
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. 在浏览器中打开 `http://localhost:8007/test-runner.html`
|
|||
|
|
|
|||
|
|
3. 点击 "▶ Run All Tests"(运行所有测试)按钮
|
|||
|
|
|
|||
|
|
就这么简单!无需 npm,无需 package.json,无需任何依赖。
|
|||
|
|
|
|||
|
|
## 测试覆盖
|
|||
|
|
|
|||
|
|
### `recorder.test.browser.js`
|
|||
|
|
- ✅ `checkMicrophoneAvailability()` - 当麦克风可用时返回 true
|
|||
|
|
- ✅ `checkMicrophoneAvailability()` - 当麦克风不可用时返回 false
|
|||
|
|
- ✅ `checkMicrophoneAvailability()` - 当浏览器不支持 getUserMedia 时返回 false
|
|||
|
|
- ✅ `isHttpNonLocalhost()` - 对于 HTTP 非本地访问返回 true
|
|||
|
|
- ✅ `isHttpNonLocalhost()` - 对于 localhost 返回 false
|
|||
|
|
- ✅ `isHttpNonLocalhost()` - 对于 127.0.0.1 返回 false
|
|||
|
|
- ✅ `isHttpNonLocalhost()` - 对于私有 IP 地址返回 false
|
|||
|
|
- ✅ `isHttpNonLocalhost()` - 对于 HTTPS 协议返回 false
|
|||
|
|
|
|||
|
|
### `tools.test.browser.js`
|
|||
|
|
- ✅ `executeMcpTool('live2d.smile')` - 执行 FlickUp 动作
|
|||
|
|
- ✅ `executeMcpTool('live2d.wave')` - 执行 Tap 动作
|
|||
|
|
- ✅ `executeMcpTool('live2d.action')` - 执行自定义动作
|
|||
|
|
- ✅ `executeMcpTool()` - 优雅处理缺失的 Live2D 管理器
|
|||
|
|
- ✅ `executeMcpTool()` - 优雅处理未知工具
|
|||
|
|
|
|||
|
|
## 编写新测试
|
|||
|
|
|
|||
|
|
添加新功能时,创建一个遵循以下模式的 `.browser.js` 测试文件:
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// your-module.test.browser.js
|
|||
|
|
import { yourFunction } from './your-module.js';
|
|||
|
|
|
|||
|
|
describe('您的功能', () => {
|
|||
|
|
beforeEach(() => {
|
|||
|
|
// 设置模拟并重置状态
|
|||
|
|
vi.clearAllMocks();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('应该执行某些操作', () => {
|
|||
|
|
// 准备
|
|||
|
|
const input = 'test';
|
|||
|
|
|
|||
|
|
// 执行
|
|||
|
|
const result = yourFunction(input);
|
|||
|
|
|
|||
|
|
// 断言
|
|||
|
|
expect(result).toBe('expected');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 模拟指南
|
|||
|
|
|
|||
|
|
- 使用 `vi.fn()` 创建函数模拟
|
|||
|
|
- 使用 `vi.fn().mockResolvedValue(value)` 创建解析的异步模拟
|
|||
|
|
- 使用 `vi.fn().mockRejectedValue(error)` 创建拒绝的异步模拟
|
|||
|
|
- 在 `beforeEach` 中使用 `vi.clearAllMocks()` 重置状态
|
|||
|
|
- 模拟浏览器 API(`navigator`、`window.location`、`localStorage`、`fetch`)
|
|||
|
|
- 需要时模拟 DOM 元素(`document.getElementById` 等)
|
|||
|
|
|
|||
|
|
## 可用的测试函数
|
|||
|
|
|
|||
|
|
浏览器测试框架提供:
|
|||
|
|
- `describe(name, fn)` - 定义测试套件
|
|||
|
|
- `test(name, fn)` - 定义测试用例
|
|||
|
|
- `beforeEach(fn)` - 在每个测试之前运行
|
|||
|
|
- `afterEach(fn)` - 在每个测试之后运行
|
|||
|
|
- `expect(actual)` - 断言对象,包含:
|
|||
|
|
- `.toBe(expected)` - 严格相等
|
|||
|
|
- `.toHaveBeenCalled()` - 函数已被调用
|
|||
|
|
- `.toHaveBeenCalledWith(...args)` - 函数已使用特定参数调用
|
|||
|
|
- `.toContain(substring)` - 字符串包含子字符串
|
|||
|
|
- `vi.fn(impl?)` - 创建模拟函数
|
|||
|
|
- `vi.clearAllMocks()` - 清除所有模拟
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
- 测试使用 ES 模块(`import`/`export`)
|
|||
|
|
- 测试直接在浏览器中运行(无需 Node.js)
|
|||
|
|
- 无需 npm 依赖 - 所有内容都是自包含的
|
|||
|
|
- 测试运行器(`test-runner.html`)包含一个简单的测试框架
|
|||
|
|
- 点击 "Run All Tests"(运行所有测试)时自动加载测试
|