Files
xlwings/README.md
Misaka 15e9fabf25 docs: update README.md with current project structure and features
- Add project status and completion indicator
- Add comprehensive project structure documentation
- Enhance installation instructions with virtual environment setup
- Add development tools section with VS Code debugging configuration
- Document --all flag for full project testing
- Add references to flowchart and implementation summary documentation
- Update FAQ with new questions about debugging and virtual environment
- Reflect current implementation features (call chain tracking, class module support, etc.)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-04 23:37:10 +08:00

501 lines
14 KiB
Markdown
Raw 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.
# VBA 自动化测试与精确报错系统
通过代码编织Code Weaving技术实现 VBA 宏的精确到行的代码报错定位,并支持完整的调用链追踪。
## 项目状态
**已完成** - 所有核心功能已实现并测试通过
## 核心特性
- **精确行号定位**: 捕获 VBA 错误的具体行号,不再只是"发生意外"
- **源代码映射**: 通过 Source Map 机制显示出错行的原始代码
- **调用链追踪**: 完整记录过程调用栈,追踪错误传播路径
- **全项目测试**: 自动发现并测试所有可测试的过程
- **模块级支持**: 支持标准模块和类模块的测试
- **非侵入式**: 测试过程不修改原始 Excel 文件
- **详细报告**: 提供清晰的测试结果输出,包含错误位置、源代码和调用链
## 项目结构
```
xlwings/
├── vba_test_runner.py # 主脚本 - 核心测试系统实现
├── demo.xlsm # 演示 Excel 文件(包含测试用例)
├── README.md # 项目文档(本文件)
├── vba_test_runner_flowchart.md # 详细流程图文档Mermaid 图表)
├── IMPLEMENTATION_SUMMARY.md # 实现总结与技术细节
├── CLAUDE.md # Claude Code 开发指南
├── .gitignore # Git 忽略规则
├── .vscode/
│ └── launch.json # VS Code 调试配置
└── .venv/ # Python 虚拟环境(需自行创建)
```
## 安装依赖
### 1. 创建虚拟环境(推荐)
```bash
# Windows
python -m venv .venv
.venv\Scripts\activate
# Linux/Mac
python3 -m venv .venv
source .venv/bin/activate
```
### 2. 安装依赖包
```bash
pip install xlwings pywin32
```
### 3. 配置 Excel 信任设置
在运行测试前,需要启用 VBA 项目对象模型访问:
1. 打开 Excel
2. 文件 > 选项 > 信任中心
3. 信任中心设置 > 宏设置
4. 勾选"信任对 VBA 工程对象模型的访问"
5. 重启 Excel
## 快速开始
### 1. 使用演示文件测试
项目包含 `demo.xlsm` 演示文件,包含以下测试用例:
首先创建一个包含测试代码的 Excel 文件:
```bash
python create_demo.py
```
这将创建 `demo.xlsm` 文件,包含以下测试过程:
- `TestErrorProcedure`: 除以零错误
- `TestTypeMismatch`: 类型不匹配错误
- `TestSubscriptError`: 下标越界错误
- `TestSuccessfulProcedure`: 成功执行的测试
### 2. 运行测试
测试单个过程:
```bash
python vba_test_runner.py demo.xlsm Module1 TestSuccessfulProcedure
```
批量测试多个过程:
```bash
python vba_test_runner.py demo.xlsm Module1 TestErrorProcedure TestTypeMismatch TestSubscriptError TestSuccessfulProcedure
```
**全项目自动化测试**(自动发现并测试所有过程):
```bash
python vba_test_runner.py demo.xlsm --all
```
## 输出示例
### 单个测试
**成功时**:
```
[PASS] TestSuccessfulProcedure
```
**失败时**(包含调用链):
```
[FAIL] TestErrorProcedure
Error: Division by zero
Location: Module1.TestErrorProcedure:30
Call Chain: Module1.MainProc -> Module1.TestErrorProcedure
Source: result = x / y
```
### 批量测试
```
===== VBA 批量测试结果 =====
[1/4] [FAIL] TestErrorProcedure
Error: Division by zero
Location: Module1.TestErrorProcedure:30
Source: result = x / y
[2/4] [FAIL] TestTypeMismatch
Error: Type mismatch
Location: Module1.TestTypeMismatch:20
Source: y = x
[3/4] [FAIL] TestSubscriptError
Error: Subscript out of range
Location: Module1.TestSubscriptError:40
Source: value = arr(5)
[4/4] [PASS] TestSuccessfulProcedure
===== Test Summary =====
Passed: 1/4
Failed: 3/4
```
### 全项目测试(--all 模式)
```
===== VBA 全项目自动化测试 =====
发现 8 个可测试的入口点
总过程数: 12
[1/8] 测试 Module1.TestErrorProcedure
[FAIL] TestErrorProcedure
Error: Division by zero
Location: Module1.TestErrorProcedure:30
Call Chain: Module1.TestErrorProcedure
Source: result = x / y
[2/8] 测试 Module1.TestSuccessfulProcedure
[PASS] TestSuccessfulProcedure
...
===== Test Summary =====
Passed: 5/8
Failed: 3/8
```
## 工作原理
### 代码编织Code Weaving
系统通过以下步骤实现精确报错:
1. **解析 VBA 代码**: 识别所有 Sub/Function 过程
2. **注入行号标签**: 在可执行代码前插入数字标签10, 20, 30...
3. **注入调用栈管理**: 添加 `LogEntry``LogExit` 调用
4. **注入错误处理**: 添加 `On Error GoTo` 语句和错误处理块
5. **创建 Source Map**: 维护行号到源代码的映射
### VBA 行号机制
VBA 的 `Erl` 函数会返回最近执行的行号标签:
```vba
10 x = 10
20 y = 0
30 result = x / y ' Erl 将返回 30
```
### 调用链追踪
系统使用 `CallStack` 类模块追踪过程调用:
```vba
Sub LogEntry(procName, moduleName)
CallStack.Push procName, moduleName
End Sub
Sub LogExit()
CallStack.Pop
End Sub
Function GetCallChain() As String
GetCallChain = CallStack.GetCallChain() ' 返回 "Module1.Main -> Module1.Helper"
End Function
```
### 测试流程
```
原始 VBA 代码
代码编织器注入行号、调用栈管理和错误处理
注入 TestLogger 模块和 CallStack 类模块
热替换目标模块代码
执行 VBA 宏
从 TestLogger 读取结果(包含调用链)
格式化输出
```
## 架构设计
### 核心类
```
vba_test_runner.py
├── TestResult (测试结果数据类)
│ ├── procedure_name - 过程名称
│ ├── success - 测试是否成功
│ ├── error_number - 错误代码
│ ├── error_description - 错误描述
│ ├── error_line - 错误行号
│ ├── source_code - 源代码
│ ├── error_module - 错误发生的模块 (新增)
│ └── call_chain - 完整调用链 (新增)
├── CodeWeaver (代码编织器类)
│ ├── parse_modules() - 解析所有模块
│ ├── parse_procedures() - 解析 VBA 过程
│ ├── weave_procedure() - 编织单个过程
│ ├── weave_procedure_with_callstack() - 编织过程(带调用栈)
│ ├── weave_module_all_procedures() - 编织模块的所有过程
│ ├── weave_all_modules() - 编织所有模块
│ ├── _inject_line_numbers() - 注入行号标签
│ ├── _inject_error_handler() - 注入错误处理
│ └── _inject_error_handler_with_callstack() - 注入错误处理(带调用栈)
├── LoggerInjector (日志模块注入器类)
│ ├── inject_or_replace() - 注入或替换 Logger 模块
│ ├── LOGGER_MODULE_CODE - TestLogger 模块的 VBA 代码
│ └── CALLSTACK_CLASS_CODE - CallStack 类模块的 VBA 代码
└── TestRunner (执行控制器类)
├── run_test() - 执行单个测试
├── run_all_tests() - 执行全项目测试 (新增)
├── discover_all_tests() - 发现所有可测试过程 (新增)
├── _get_vba_code() - 读取 VBA 代码
├── _replace_module_code() - 热替换模块代码
├── _execute_macro() - 执行宏
├── _get_test_result() - 获取测试结果
├── _is_entry_point() - 判断是否为测试入口点 (新增)
├── _weave_all_modules_inplace() - 就地编织所有模块 (新增)
└── _run_single_test() - 执行单个测试(批量用) (新增)
```
### TestResult 结构
```python
@dataclass
class TestResult:
procedure_name: str # 过程名称
success: bool # 测试是否成功
error_number: int = 0 # 错误代码
error_description: str = "" # 错误描述
error_line: int = 0 # 错误行号
source_code: str = "" # 源代码
error_module: str = "" # 错误发生的模块
call_chain: str = "" # 完整调用链 (如: "Module1.A -> Module1.B")
```
## 关键技术点
### 行号标签规则
- 使用纯数字标签: `10`, `20`, `30`... (不带冒号)
- 只在可执行代码前注入
- 跳过声明区Dim, Private 等)
- 跳过注释行和空行
- 跳过现有的 On Error 语句
### 错误处理模板(带调用栈)
```vba
Call TestLogger.LogEntry("{proc_name}", "{module_name}")
On Error GoTo Auto_Err_Handler_{proc_name}
... 原有代码 ...
Call TestLogger.LogExit()
Call TestLogger.LogSuccess()
Exit Sub/Function
Auto_Err_Handler_{proc_name}:
Call TestLogger.LogError("{proc_name}", "{module_name}", Err.Number, Err.Description, Erl)
Call TestLogger.LogExit()
```
### CallStack 类模块
```vba
' CallStack 类维护调用栈
Private m_Stack As Collection
Public Sub Push(procName, moduleName)
m_Stack.Add moduleName & "." & procName
End Sub
Public Sub Pop()
m_Stack.Remove m_Stack.Count
End Sub
Public Function GetCallChain() As String
' 返回 "Module1.A -> Module1.B -> Module2.C"
GetCallChain = Join(parts, " -> ")
End Function
```
### 热替换不保存
使用 `wb.Close(SaveChanges=False)` 确保注入的代码不会污染原始文件。
## 限制和注意事项
1. **信任访问 VBA 项目**: 需要在 Excel 信任中心启用"信任对 VBA 工程对象模型的访问"
- 路径: 文件 > 选项 > 信任中心 > 信任中心设置 > 宏设置 > 勾选"信任对 VBA 工程对象模型的访问"
2. **行号标签冲突**: 如果原始代码中已使用相同数值的行号标签,可能会产生冲突
3. **复杂过程**: 对于非常复杂的过程(包含大量 GoTo 语句),可能需要额外处理
4. **模块类型支持**: 支持标准模块Type 1和类模块Type 2不支持窗体模块Type 3
5. **过程过滤**: 全项目测试模式会自动排除以下过程:
-`Worksheet_``Workbook_``Document_` 开头的事件过程
- Logger 相关过程LogEntry、LogExit、LogError 等)
## 扩展开发
### 添加新的测试过程
在 Excel 文件的 VBA 模块中添加你的测试过程:
```vba
Sub YourTestProcedure()
' 你的测试代码
End Sub
```
然后运行:
```bash
python vba_test_runner.py your_file.xlsm Module1 YourTestProcedure
```
### 使用全项目测试
全项目测试模式会自动发现并测试所有过程:
```bash
python vba_test_runner.py your_file.xlsm --all
```
系统会:
1. 扫描所有标准模块和类模块
2. 识别所有 Sub/Function 过程
3. 过滤掉事件过程和内部方法
4. 为所有模块注入调用栈管理
5. 逐个执行测试并生成报告
### 自定义 Logger 模块
修改 `LoggerInjector.LOGGER_MODULE_CODE``CALLSTACK_CLASS_CODE` 可以自定义日志记录逻辑。
### 程序化使用
```python
from vba_test_runner import TestRunner
# 单个测试
runner = TestRunner("demo.xlsm", visible=False)
result = runner.run_test("Module1", "TestErrorProcedure")
# 全项目测试
runner = TestRunner("demo.xlsm", visible=False)
results = runner.run_all_tests()
# 发现所有测试
tests = runner.discover_all_tests()
for test in tests:
print(f"{test['module']}.{test['procedure']}")
```
## 开发工具
### VS Code 调试配置
项目包含 `.vscode/launch.json` 调试配置,可直接在 VS Code 中调试:
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: VBA Test Runner",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/vba_test_runner.py",
"console": "integratedTerminal",
"args": ["demo.xlsm", "--all"]
}
]
}
```
使用方法:
1. 在 VS Code 中打开项目
2.`F5` 或点击调试面板
3. 选择 "Python: VBA Test Runner" 配置
4. 可以在 `launch.json` 中修改 `args` 来测试不同的场景
### 查看流程图
详细的技术流程图请查看 [vba_test_runner_flowchart.md](vba_test_runner_flowchart.md),包含:
- 系统架构概览
- 单个测试执行流程
- 全项目测试流程
- 代码编织流程
- 错误处理与调用链追踪
- 类关系图
### 实现总结
查看 [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) 了解:
- 项目完成状态
- 已测试的验证场景
- 关键技术实现细节
- 已解决的问题
## 常见问题
**Q: 为什么测试后原始文件没有被修改?**
A: 系统使用热替换技术,在内存中修改代码,测试完成后使用 `Close(SaveChanges=False)` 不保存更改。
**Q: 如何测试类模块中的方法?**
A: 系统支持类模块Type 2的测试。在全项目测试模式下类模块中的公共方法会被自动发现和测试。
**Q: 调用链是如何追踪的?**
A: 系统在每个过程入口注入 `LogEntry` 调用,在出口注入 `LogExit` 调用。`CallStack` 类模块维护一个栈结构,记录所有正在执行的过程,错误发生时可以生成完整的调用链。
**Q: 全项目测试模式和手动指定过程有什么区别?**
A: 全项目测试模式(`--all`)会:
- 自动发现所有可测试的过程
- 一次性编织所有模块的代码
- 逐个执行测试并生成汇总报告
- 更适合大规模测试和回归测试
手动指定过程模式更适合:
- 调试单个过程
- 快速验证修复
- 选择性测试某些功能
**Q: 如何在 VS Code 中调试?**
A: 项目包含 `.vscode/launch.json` 配置文件。在 VS Code 中按 `F5` 即可启动调试,可以在配置中修改测试参数。
**Q: 可以捕获运行时警告吗?**
A: 当前版本只捕获错误。要捕获警告,需要修改 Logger 模块来处理 `InfoMessage` 事件。
**Q: 虚拟环境是必须的吗?**
A: 强烈推荐使用虚拟环境来隔离项目依赖。项目包含 `.gitignore` 规则来忽略虚拟环境目录。
## 许可证
MIT License
## 贡献
欢迎提交 Issue 和 Pull Request