# VBA 自动化测试系统 - 流程图文档 ## 目录 1. [系统架构概览](#系统架构概览) 2. [单个测试执行流程](#单个测试执行流程) 3. [全项目测试流程](#全项目测试流程) 4. [代码编织流程](#代码编织流程) 5. [错误处理与调用链追踪](#错误处理与调用链追踪) 6. [类关系图](#类关系图) --- ## 系统架构概览 ### 整体数据流 ```mermaid graph TB A[用户输入测试请求] --> B{测试模式} B -->|单个过程| C[run_test] B -->|全项目| D[run_all_tests] C --> E[TestRunner 初始化] D --> E E --> F[CodeWeaver 解析 VBA 模块] F --> G[注入行号标签和错误处理] G --> H[LoggerInjector 注入日志模块] H --> I[热替换模块代码] I --> J[执行 VBA 宏] J --> K[捕获执行结果] K --> L[返回 TestResult] L --> M{测试成功?} M -->|是| N[显示成功信息] M -->|否| O[显示详细错误信息] O --> P[包含错误位置、源代码、调用链] N --> Q[清理资源,关闭 Excel] P --> Q style A fill:#e1f5ff style N fill:#c8e6c9 style O fill:#ffcdd2 style Q fill:#fff9c4 ``` --- ## 单个测试执行流程 ### TestRunner.run_test() 详细流程 ```mermaid flowchart TD Start([开始: run_test]) --> OpenExcel[1. 打开 Excel 文件
xw.App.visible] OpenExcel --> ReadCode[2. 读取原始 VBA 代码
_get_vba_code] ReadCode --> WeaveCode[3. 编织模块代码
weave_module_all_procedures] WeaveCode --> ParseProcs[3.1 解析所有过程
parse_procedures] ParseProcs --> InjectLineNum[3.2 注入行号标签
_inject_line_numbers] InjectLineNum --> InjectErrHandler[3.3 注入错误处理和调用栈
_inject_error_handler_with_callstack] InjectErrHandler --> InjectLogger[4. 注入 Logger 模块
inject_or_replace] InjectLogger --> ReplaceCode[5. 热替换模块代码
_replace_module_code] ReplaceCode --> Execute[6. 执行宏
_execute_macro] Execute --> GetResult[7. 获取测试结果
_get_test_result] GetResult --> CheckResult{结果字符串} CheckResult -->|SUCCESS| CreateSuccess[创建成功 TestResult] CheckResult -->|ERROR| ParseError[解析错误信息字符串
格式: ERROR + 模块.过程 + 行号 + 编号 + 描述 + 调用链] ParseError --> ExtractInfo[提取错误模块、过程、行号] ExtractInfo --> LookupSource[从 Source Map 查找源代码
source_map[line]] LookupSource --> CreateError[创建失败 TestResult] CreateSuccess --> Cleanup[8. 清理资源
_cleanup] CreateError --> Cleanup Cleanup --> End([结束]) 异常处理[Exception] --> CreateErrorResult[创建异常 TestResult] CreateErrorResult --> Cleanup style Start fill:#e1f5ff style End fill:#e1f5ff style CreateSuccess fill:#c8e6c9 style CreateError fill:#ffcdd2 style Cleanup fill:#fff9c4 ``` --- ## 全项目测试流程 ### TestRunner.run_all_tests() 批量测试流程 ```mermaid flowchart TD Start([开始: run_all_tests]) --> Discover[发现所有测试
discover_all_tests] Discover --> ParseModules[解析 VBA 项目
parse_modules] ParseModules --> IterateModules[遍历所有模块] IterateModules --> IterateProcs[遍历每个过程] IterateProcs --> CheckEntry{是否是入口点?
_is_entry_point} CheckEntry -->|排除事件/Logger过程| Filter[过滤掉] CheckEntry -->|是| AddToList[添加到测试列表] AddToList --> Filter Filter --> MoreModules{更多模块?} MoreModules -->|是| IterateModules MoreModules -->|否| PrintStats[打印统计信息
总过程数、可测试数] PrintStats --> OpenExcel[打开 Excel 文件] OpenExcel --> WeaveAll[一次性编织所有模块
_weave_all_modules_inplace] WeaveAll --> InjectLoggerModule[注入 TestLogger 和 CallStack] InjectLoggerModule --> WeaveEach[编织每个模块] WeaveEach --> ReplaceAll[热替换所有模块代码] ReplaceAll --> RunTests[执行所有测试] RunTests --> TestLoop[遍历入口点测试] TestLoop --> InitLogger[初始化 TestLogger
Initialize] InitLogger --> RunSingle[执行单个测试
_run_single_test] RunSingle --> ExecuteMacro[执行宏] ExecuteMacro --> GetSingleResult[获取结果] GetSingleResult --> PrintResult[打印测试结果
print_test_result] PrintResult --> MoreTests{更多测试?} MoreTests -->|是| TestLoop MoreTests -->|否| PrintSummary[打印测试汇总
print_summary] PrintSummary --> Cleanup[清理资源] Cleanup --> End([结束]) style Start fill:#e1f5ff style End fill:#e1f5ff style PrintStats fill:#fff9c4 style PrintSummary fill:#fff9c4 style Cleanup fill:#ffe0b2 ``` --- ## 代码编织流程 ### CodeWeaver 代码注入详细流程 ```mermaid flowchart TD Start([开始: weave_procedure_with_callstack]) --> Parse[解析过程
parse_procedures] Parse --> FindProc{找到过程?} FindProc -->|否| Error[抛出 ValueError] FindProc -->|是| ExtractLines[提取过程代码行
start_line 到 end_line] ExtractLines --> InjectLineNums[注入行号标签
_inject_line_numbers] InjectLineNums --> InitCounter[初始化计数器 = 10] InitCounter --> LineLoop[遍历代码行] LineLoop --> CheckLine{检查行类型} CheckLine -->|声明行| SkipDec[跳过] CheckLine -->|注释行| SkipComment[跳过] CheckLine -->|空行| SkipEmpty[跳过] CheckLine -->|On Error| SkipOnError[跳过] CheckLine -->|过程定义/结束| SkipProc[跳过] CheckLine -->|可执行代码| AddLabel[添加行号标签
10, 20, 30...] AddLabel --> SaveToMap[保存到 source_map
行号 -> 源代码] SaveToMap --> Increment[计数器 += 10] SkipDec --> MoreLines{更多行?} SkipComment --> MoreLines SkipEmpty --> MoreLines SkipOnError --> MoreLines SkipProc --> MoreLines Increment --> MoreLines MoreLines -->|是| LineLoop MoreLines -->|否| InjectHandler[注入错误处理
_inject_error_handler_with_callstack] InjectHandler --> DetermineType[确定过程类型
Sub or Function] DetermineType --> RemoveExisting[删除现有 On Error] RemoveExisting --> InsertLogEntry[在第一个可执行语句后插入:
TestLogger.LogEntry
On Error GoTo Handler] InsertLogEntry --> InsertExitBlock[在 End 前插入退出块:
TestLogger.LogExit
TestLogger.LogSuccess
Exit Sub/Function] InsertExitBlock --> InsertHandlerBlock[插入错误处理块:
Auto_Err_Handler:
TestLogger.LogError
TestLogger.LogExit] InsertHandlerBlock --> ReplaceProc[替换原过程] ReplaceProc --> Return[返回编织后的代码
和 source_map] Return --> End([结束]) Error --> End style Start fill:#e1f5ff style End fill:#e1f5ff style AddLabel fill:#c8e6c9 style InsertLogEntry fill:#b3e5fc style InsertHandlerBlock fill:#ffccbc ``` ### 行号标签注入规则 ```mermaid graph TD A[原始 VBA 代码] --> B{行类型判断} B --> C[声明块
Dim/Private/Public/Const] B --> D[注释行
' 开头] B --> E[空行] B --> F[On Error 语句] B --> G[过程定义行
Sub/Function] B --> H[过程结束行
End Sub/Function] B --> I[退出语句
Exit Sub/Function] B --> J[可执行代码] C --> Z[跳过,不注入] D --> Z E --> Z F --> Z G --> Z H --> Z I --> Z J --> K[注入行号标签
10, 20, 30...] K --> L[记录到 source_map] style C fill:#ffcdd2 style D fill:#ffcdd2 style E fill:#ffcdd2 style F fill:#ffcdd2 style G fill:#ffcdd2 style H fill:#ffcdd2 style I fill:#ffcdd2 style J fill:#c8e6c9 style Z fill:#ffe0b2 ``` --- ## 错误处理与调用链追踪 ### TestLogger 和 CallStack 工作流程 ```mermaid sequenceDiagram participant Test as 测试流程 participant Logger as TestLogger participant Stack as CallStack participant VBA as VBA 过程 Test->>Logger: Initialize() Logger->>Logger: m_TestStatus = "SUCCESS" Test->>VBA: 调用过程 A VBA->>Logger: LogEntry("A", "Module1") Logger->>Stack: Push("A", "Module1") Stack->>Stack: m_Stack.Add("Module1.A") VBA->>VBA: 执行代码 (带行号标签) alt 过程 A 调用过程 B VBA->>Logger: LogEntry("B", "Module1") Logger->>Stack: Push("B", "Module1") Stack->>Stack: m_Stack.Add("Module1.B") VBA->>VBA: 执行代码 Note over VBA: 20: x = 1 / 0 ❌ 除零错误 VBA->>Logger: LogError("B", "Module1", 11, "Division by zero", 20) Logger->>Logger: m_TestStatus = "ERROR" Logger->>Stack: GetCallChain() Stack-->>Logger: "Module1.A -> Module1.B" Logger->>Logger: 保存错误信息 VBA->>Logger: LogExit() Logger->>Stack: Pop() end VBA->>Logger: LogExit() Logger->>Stack: Pop() Test->>Logger: GetResult() Logger-->>Test: "ERROR + Module1.B + 20 + 11 + Division by zero + Module1.A -> Module1.B" Test->>Test: 解析错误信息 Test->>Test: 从 source_map[20] 获取源代码 Test-->>User: 显示详细错误报告 ``` ### 错误信息传递流程 ```mermaid flowchart LR A[VBA 运行时错误] --> B[On Error GoTo 捕获] B --> C[跳转到 Auto_Err_Handler] C --> D[调用 TestLogger.LogError] D --> E[设置 m_TestStatus = ERROR] E --> F[保存错误信息:
模块、过程、行号、编号、描述] F --> G[从 CallStack 获取调用链] G --> H[TestRunner 调用 GetResult] H --> I{检查 m_TestStatus} I -->|SUCCESS| J[返回 "SUCCESS"] I -->|ERROR| K[构造错误字符串:
ERROR + 模块.过程 + 行号 + 编号 + 描述 + 调用链] K --> L[TestRunner 解析字符串] L --> M[提取错误模块、过程、行号] M --> N[从 source_map 查找源代码] N --> O[构造 TestResult 对象] O --> P[显示详细错误报告] style A fill:#ffcdd2 style J fill:#c8e6c9 style K fill:#ffccbc style P fill:#fff9c4 ``` --- ## 类关系图 ### 系统类结构与依赖关系 ```mermaid classDiagram class TestResult { +str procedure_name +bool success +int error_number +str error_description +int error_line +str source_code +str error_module +str call_chain } class CodeWeaver { -int line_counter +parse_modules(vba_project) Dict +parse_procedures(code) Dict +weave_procedure_with_callstack(code, proc_name, module_name) Tuple +weave_module_all_procedures(code, module_name) Tuple +weave_all_modules(modules) Dict -_inject_line_numbers(lines) Tuple -_inject_error_handler_with_callstack(lines, proc_name, module_name) List -_get_component_code(component) str } class LoggerInjector { +str CALLSTACK_CLASS_CODE +str LOGGER_MODULE_CODE +inject_or_replace(wb, module_name) None } class TestRunner { +str file_path +bool visible +CodeWeaver code_weaver +LoggerInjector logger_injector +Dict source_map +run_test(module_name, proc_name) TestResult +run_all_tests() List~TestResult~ +discover_all_tests() List~Dict~ -_get_vba_code(module_name) str -_replace_module_code(module_name, new_code) None -_execute_macro(proc_name) None -_get_test_result(proc_name) TestResult -_cleanup() None } class TestLogger { <> +LogEntry(procName, moduleName) +LogExit() +LogError(procName, moduleName, errNum, errDesc, errLine) +LogSuccess() +GetResult() String +Initialize() } class CallStack { <> -Collection m_Stack +Push(procName, moduleName) +Pop() +GetCallChain() String +Clear() } TestRunner --> CodeWeaver : 使用 TestRunner --> LoggerInjector : 使用 TestRunner --> TestResult : 创建 LoggerInjector --> TestLogger : 注入 LoggerInjector --> CallStack : 注入 TestLogger --> CallStack : 使用 CodeWeaver --> TestResult : 生成 source_map ``` ### 模块交互时序图 ```mermaid sequenceDiagram participant User as 用户 participant Main as main() participant Runner as TestRunner participant Weaver as CodeWeaver participant Injector as LoggerInjector participant Excel as Excel Application User->>Main: 执行命令 Main->>Runner: 初始化(file_path, visible=False) alt 单个测试模式 Main->>Runner: run_test(module, proc) else 全项目测试模式 Main->>Runner: run_all_tests() Runner->>Runner: discover_all_tests() Runner->>Runner: _weave_all_modules_inplace() end Runner->>Excel: 打开工作簿 Runner->>Weaver: parse_modules(vba_project) Weaver-->>Runner: 模块信息 Runner->>Weaver: weave_module_all_procedures(code, module) Weaver->>Weaver: _inject_line_numbers() Weaver->>Weaver: _inject_error_handler_with_callstack() Weaver-->>Runner: woven_code, source_map Runner->>Injector: inject_or_replace(wb) Injector->>Excel: 删除旧的 TestLogger/CallStack Injector->>Excel: 添加新的 CallStack 类模块 Injector->>Excel: 添加新的 TestLogger 模块 Runner->>Excel: _replace_module_code(module, woven_code) Runner->>Excel: _execute_macro(module.proc) Excel-->>Runner: 执行结果 Runner->>Excel: TestLogger.GetResult() Excel-->>Runner: "SUCCESS" 或 "ERROR|..." Runner-->>Main: TestResult Main-->>User: 打印测试结果 Runner->>Excel: _cleanup() Excel->>Excel: 关闭工作簿(不保存) Excel->>Excel: 退出 Excel ``` --- ## 附录:关键数据结构 ### TestResult 数据类 ```mermaid graph TD A[TestResult 数据类] --> B[procedure_name: str
被测试的过程名称] A --> C[success: bool
测试是否成功] A --> D[error_number: int
VBA 错误编号] A --> E[error_description: str
错误描述信息] A --> F[error_line: int
错误发生的行号标签] A --> G[source_code: str
错误行的原始源代码] A --> H[error_module: str
错误发生的模块名] A --> I[call_chain: str
完整调用链
Module1.ProcA -> Module1.ProcB] style A fill:#e1f5ff style C fill:#c8e6c9 style F fill:#fff9c4 style G fill:#fff9c4 style I fill:#ffccbc ``` ### Source Map 映射关系 ```mermaid graph LR A[原始 VBA 代码] -->|CodeWeaver 处理| B[编织后的代码] B --> C[行号标签 10
x = 1] B --> D[行号标签 20
y = x / 0 ❌] B --> E[行号标签 30
z = y + 1] C --> F[source_map[10] = 'x = 1'] D --> G[source_map[20] = 'y = x / 0'] E --> H[source_map[30] = 'z = y + 1'] G --> I[VBA 错误发生在行 20] I --> J[通过 source_map[20]
获取原始源代码] J --> K[显示给用户:
y = x / 0] style A fill:#e1f5ff style B fill:#c8e6c9 style G fill:#ffcdd2 style K fill:#fff9c4 ``` --- ## 使用示例流程 ### 命令行使用模式 ```mermaid flowchart TD Start([用户执行命令]) --> CheckArgs{参数检查} CheckArgs -->|python vba_test_runner.py| ShowHelp1[显示用法1] CheckArgs -->|python vba_test_runner.py file.xlsm --all| AllTest[全项目测试模式] CheckArgs -->|python vba_test_runner.py file.xlsm Module Proc1 Proc2| SingleTest[单过程/多过程测试模式] ShowHelp1 --> End1([结束]) AllTest --> InitRunner1[初始化 TestRunner
visible=False] InitRunner1 --> RunAll[执行 run_all_tests] RunAll --> Discover[发现所有过程] Discover --> WeaveAllModules[编织所有模块] WeaveAllModules --> BatchExecute[批量执行测试] BatchExecute --> ShowSummary[显示测试汇总] ShowSummary --> Cleanup1[清理资源] Cleanup1 --> End2([结束]) SingleTest --> InitRunner2[初始化 TestRunner
visible=False] InitRunner2 --> LoopProcs[循环遍历过程列表] LoopProcs --> RunSingle[执行 run_test] RunSingle --> ShowSingleResult[显示单个结果] ShowSingleResult --> MoreProcs{更多过程?} MoreProcs -->|是| LoopProcs MoreProcs -->|否| ShowSummary2[显示测试汇总] ShowSummary2 --> Cleanup2[清理资源] Cleanup2 --> End3([结束]) style Start fill:#e1f5ff style End1 fill:#e1f5ff style End2 fill:#e1f5ff style End3 fill:#e1f5ff style AllTest fill:#c8e6c9 style SingleTest fill:#b3e5fc ``` --- ## 总结 该 VBA 自动化测试系统通过**代码编织技术**实现了: 1. **非侵入式测试**:在内存中修改代码,不保存到磁盘 2. **精确行号定位**:通过行号标签和 Source Map 实现源代码映射 3. **调用链追踪**:通过 CallStack 类追踪完整调用路径 4. **批量测试支持**:支持单过程和全项目两种测试模式 5. **详细错误报告**:包含错误位置、源代码、调用链等完整信息 系统的核心创新在于将编译器中的**代码编织技术**应用于 VBA 动态测试,通过在运行时注入检测代码来实现传统 IDE 无法提供的调试功能。