feat: implement BOM auto-extraction system
All checks were successful
NTFY Notification / notify (push) Successful in 11s
All checks were successful
NTFY Notification / notify (push) Successful in 11s
Add complete BOM auto-extraction system with the following modules: - M06_ModelParser: Parse product model strings to extract parameters (azxs, bkxs, gclj, jycz, lcfw, fjgn) - Extracts header part from full model (ignores dial/attachment parts) - Splits process connection and material code (G123 -> G12, 3) - Supports multiple additional features with comma/dot separators - M07_BOMMatcher: Match materials in BOM library - Exact match, wildcard (empty cell), negative match (!=) - Special fjgn contains matching logic - Array-based performance optimization for bulk operations - M08_ComponentProcessor: Handle component material special logic - Component inventory check (interface reserved) - Sub-component extraction (joint + elastic element) - Combination validation rules (1 component OR 1 joint + 1 element) - M09_BOMExtractor: Main extraction orchestrator - Reads input models from worksheet - Processes each model and matches all material types - Outputs to "BOM提取结果" worksheet - Error reporting and non-blocking design - M06B_TestRunner: Comprehensive unit tests - 8 test cases for model parsing - 5 test cases for BOM matching - 5 test cases for component processing - M04_Config: Add BOM extraction constants - BOM library filename and configuration - Input/output column definitions - Output column enumeration - M01_Main: Add RunBOMExtraction entry point Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
412
VBA_BOMConverter/Modules/M06B_TestRunner.bas
Normal file
412
VBA_BOMConverter/Modules/M06B_TestRunner.bas
Normal file
@@ -0,0 +1,412 @@
|
||||
' ==============================================================================
|
||||
' 模块: M06B_TestRunner
|
||||
' 职责: BOM自动提取系统的单元测试
|
||||
'
|
||||
' 测试模块:
|
||||
' - M06_ModelParser: 型号解析测试
|
||||
' - M07_BOMMatcher: BOM匹配测试
|
||||
' - M08_ComponentProcessor: 部件处理测试
|
||||
' - M09_BOMExtractor: 提取流程测试
|
||||
' ==============================================================================
|
||||
Option Explicit
|
||||
|
||||
Private m_Logger As clsErrorLogger
|
||||
Private m_FailCount As Long
|
||||
Private m_PassCount As Long
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 主入口: 运行所有BOM提取测试
|
||||
' ------------------------------------------------------------------------------
|
||||
Public Sub RunBOMExtractionTests()
|
||||
' 初始化环境
|
||||
Set m_Logger = New clsErrorLogger
|
||||
M06_ModelParser.InitModelParser m_Logger
|
||||
M07_BOMMatcher.InitBOMMatcher m_Logger
|
||||
M08_ComponentProcessor.InitComponentProcessor m_Logger
|
||||
|
||||
m_FailCount = 0
|
||||
m_PassCount = 0
|
||||
|
||||
Debug.Print String(60, "=")
|
||||
Debug.Print "开始运行BOM自动提取系统测试: " & Now
|
||||
Debug.Print String(60, "-")
|
||||
|
||||
' M06_ModelParser 测试
|
||||
Debug.Print vbCrLf & "[M06_ModelParser 测试]"
|
||||
Debug.Print String(60, "-")
|
||||
Test_MP_01_简单型号解析
|
||||
Test_MP_02_复杂型号带管道符
|
||||
Test_MP_03_过程连接与材质分离
|
||||
Test_MP_04_量程范围提取
|
||||
Test_MP_05_附加功能提取
|
||||
Test_MP_06_多个附加功能
|
||||
Test_MP_07_不完整型号验证
|
||||
Test_MP_08_空型号处理
|
||||
|
||||
' M07_BOMMatcher 测试
|
||||
Debug.Print vbCrLf & "[M07_BOMMatcher 测试]"
|
||||
Debug.Print String(60, "-")
|
||||
Test_BM_01_精确匹配
|
||||
Test_BM_02_空值通配符匹配
|
||||
Test_BM_03_否定条件匹配
|
||||
Test_BM_04_附加功能包含匹配
|
||||
Test_BM_05_fjgn包含逻辑
|
||||
|
||||
' M08_ComponentProcessor 测试
|
||||
Debug.Print vbCrLf & "[M08_ComponentProcessor 测试]"
|
||||
Debug.Print String(60, "-")
|
||||
Test_CP_01_验证仅部件
|
||||
Test_CP_02_验证接头加弹性元件
|
||||
Test_CP_03_无效组合缺少弹性元件
|
||||
Test_CP_04_无效组合重复类型
|
||||
Test_CP_05_空物料列表验证
|
||||
|
||||
' 汇总结果
|
||||
Debug.Print String(60, "-")
|
||||
If m_FailCount = 0 Then
|
||||
Debug.Print "测试结果: ALL PASS! (共 " & m_PassCount & " 个测试点)"
|
||||
Else
|
||||
Debug.Print "测试结果: 失败 " & m_FailCount & " 个, 通过 " & m_PassCount & " 个"
|
||||
End If
|
||||
Debug.Print String(60, "=")
|
||||
End Sub
|
||||
|
||||
' ==============================================================================
|
||||
' M06_ModelParser 测试用例
|
||||
' ==============================================================================
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_01: 简单型号解析
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_01_简单型号解析()
|
||||
Dim params As Object
|
||||
Set params = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M04.Y3")
|
||||
|
||||
Assert_NotNull params, "MP01_Params_Not_Null"
|
||||
Assert_Equal params.count, 8, "MP01_Params_Count"
|
||||
|
||||
Assert_Equal params("xh"), "YTHN", "MP01_xh"
|
||||
Assert_Equal params("gcwj"), "100", "MP01_gcwj"
|
||||
Assert_Equal params("azxs"), "A0", "MP01_azxs"
|
||||
Assert_Equal params("bkxs"), "531", "MP01_bkxs"
|
||||
Assert_Equal params("gclj"), "G12", "MP01_gclj"
|
||||
Assert_Equal params("jycz"), "3", "MP01_jycz"
|
||||
Assert_Equal params("lcfw"), "M04", "MP01_lcfw"
|
||||
Assert_Equal params("fjgn"), "Y3", "MP01_fjgn"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_02: 复杂型号带管道符
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_02_复杂型号带管道符()
|
||||
Dim params As Object
|
||||
Set params = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M04.Y3|BP-088.2312.B09.0A3")
|
||||
|
||||
Assert_NotNull params, "MP02_Params_Not_Null"
|
||||
Assert_Equal params("azxs"), "A0", "MP02_azxs"
|
||||
Assert_Equal params("bkxs"), "531", "MP02_bkxs"
|
||||
Assert_Equal params("lcfw"), "M04", "MP02_lcfw"
|
||||
Assert_Equal params("fjgn"), "Y3", "MP02_fjgn"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_03: 过程连接与材质分离
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_03_过程连接与材质分离()
|
||||
Dim params As Object
|
||||
Set params = M06_ModelParser.ParseProductModel("YTHN-100.BZ.531.M201.M09.Y3")
|
||||
|
||||
Assert_Equal params("gclj"), "M20", "MP03_gclj"
|
||||
Assert_Equal params("jycz"), "1", "MP03_jycz"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_04: 量程范围提取
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_04_量程范围提取()
|
||||
Dim params1 As Object
|
||||
Set params1 = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M06.Y3")
|
||||
Assert_Equal params1("lcfw"), "M06", "MP04_lcfw_M06"
|
||||
|
||||
Dim params2 As Object
|
||||
Set params2 = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M16.Y3")
|
||||
Assert_Equal params2("lcfw"), "M16", "MP04_lcfw_M16"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_05: 附加功能提取
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_05_附加功能提取()
|
||||
Dim params As Object
|
||||
Set params = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M04.N1.Y3")
|
||||
|
||||
Assert_Equal params("fjgn"), "N1,Y3", "MP05_fjgn_N1"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_06: 多个附加功能
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_06_多个附加功能()
|
||||
Dim params1 As Object
|
||||
Set params1 = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M04.N1,N2.Y3")
|
||||
Assert_Equal params1("fjgn"), "N1,N2,Y3", "MP06_fjgn_Comma"
|
||||
|
||||
Dim params2 As Object
|
||||
Set params2 = M06_ModelParser.ParseProductModel("YTHN-100.A0.531.G123.M04.N1.N2.Y3")
|
||||
Assert_Equal params2("fjgn"), "N1,N2,Y3", "MP06_fjgn_Dot"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_07: 不完整型号验证
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_07_不完整型号验证()
|
||||
Dim params As Object
|
||||
Set params = M06_ModelParser.ParseProductModel("YTHN-100.A0")
|
||||
|
||||
' 不完整型号仍应返回字典,但字段较少
|
||||
Assert_NotNull params, "MP07_Params_Not_Null"
|
||||
Assert_True params.Exists("azxs"), "MP07_Has_azxs"
|
||||
Assert_False params.Exists("bkxs"), "MP07_No_bkxs"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 MP_08: 空型号处理
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_MP_08_空型号处理()
|
||||
Dim params As Object
|
||||
Set params = M06_ModelParser.ParseProductModel("")
|
||||
|
||||
Assert_NotNull params, "MP08_Params_Not_Null"
|
||||
Assert_Equal params.count, 0, "MP08_Empty_Count"
|
||||
End Sub
|
||||
|
||||
' ==============================================================================
|
||||
' M07_BOMMatcher 测试用例
|
||||
' ==============================================================================
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 BM_01: 精确匹配
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_BM_01_精确匹配()
|
||||
Dim cellValue As String
|
||||
cellValue = "A0"
|
||||
Dim paramValue As String
|
||||
paramValue = "A0"
|
||||
|
||||
Dim result As Boolean
|
||||
result = M07_BOMMatcher.EvaluateCellCondition(cellValue, paramValue, "azxs")
|
||||
|
||||
Assert_Equal result, True, "BM01_Exact_Match"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 BM_02: 空值通配符匹配
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_BM_02_空值通配符匹配()
|
||||
Dim cellValue As Variant
|
||||
cellValue = ""
|
||||
Dim paramValue As String
|
||||
paramValue = "A0"
|
||||
|
||||
Dim result As Boolean
|
||||
result = M07_BOMMatcher.EvaluateCellCondition(cellValue, paramValue, "azxs")
|
||||
|
||||
Assert_Equal result, True, "BM02_Wildcard_Match"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 BM_03: 否定条件匹配
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_BM_03_否定条件匹配()
|
||||
Dim cellValue As String
|
||||
cellValue = "!=A0"
|
||||
Dim paramValue As String
|
||||
paramValue = "B0"
|
||||
|
||||
Dim result As Boolean
|
||||
result = M07_BOMMatcher.EvaluateCellCondition(cellValue, paramValue, "azxs")
|
||||
|
||||
Assert_Equal result, True, "BM03_Not_Equal_Match"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 BM_04: 附加功能包含匹配
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_BM_04_附加功能包含匹配()
|
||||
Dim cellValue As String
|
||||
cellValue = "N1"
|
||||
Dim fjgnList As String
|
||||
fjgnList = "N1,N2,Y3"
|
||||
|
||||
Dim result As Boolean
|
||||
result = M07_BOMMatcher.CheckFjgnMatch(cellValue, fjgnList)
|
||||
|
||||
Assert_Equal result, True, "BM04_Fjgn_Contains_N1"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 BM_05: fjgn包含逻辑
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_BM_05_fjgn包含逻辑()
|
||||
' 测试包含
|
||||
Assert_True M07_BOMMatcher.CheckFjgnMatch("N3", "N3,N2"), "BM05_Contains_N3"
|
||||
Assert_True M07_BOMMatcher.CheckFjgnMatch("N2", "N3,N2"), "BM05_Contains_N2"
|
||||
|
||||
' 测试不包含
|
||||
Assert_False M07_BOMMatcher.CheckFjgnMatch("N1", "N3,N2"), "BM05_Not_Contains_N1"
|
||||
|
||||
' 测试空列表
|
||||
Assert_False M07_BOMMatcher.CheckFjgnMatch("N1", ""), "BM05_Empty_List"
|
||||
End Sub
|
||||
|
||||
' ==============================================================================
|
||||
' M08_ComponentProcessor 测试用例
|
||||
' ==============================================================================
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 CP_01: 验证仅部件
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_CP_01_验证仅部件()
|
||||
Dim materials As Collection
|
||||
Set materials = New Collection
|
||||
|
||||
Dim mat1 As Object
|
||||
Set mat1 = CreateMaterial("部件", "部件A", "C001", 1)
|
||||
materials.Add mat1
|
||||
|
||||
Dim validation As Object
|
||||
Set validation = M08_ComponentProcessor.ValidateComponentCombination(materials)
|
||||
|
||||
Assert_Equal validation("valid"), True, "CP01_Valid_Component"
|
||||
Assert_True InStr(validation("message"), "1个部件") > 0, "CP01_Message_Content"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 CP_02: 验证接头加弹性元件
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_CP_02_验证接头加弹性元件()
|
||||
Dim materials As Collection
|
||||
Set materials = New Collection
|
||||
|
||||
Dim mat1 As Object
|
||||
Set mat1 = CreateMaterial("接头", "接头A", "J001", 1)
|
||||
materials.Add mat1
|
||||
|
||||
Dim mat2 As Object
|
||||
Set mat2 = CreateMaterial("弹性元件", "元件A", "E001", 1)
|
||||
materials.Add mat2
|
||||
|
||||
Dim validation As Object
|
||||
Set validation = M08_ComponentProcessor.ValidateComponentCombination(materials)
|
||||
|
||||
Assert_Equal validation("valid"), True, "CP02_Valid_Joint_Element"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 CP_03: 无效组合缺少弹性元件
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_CP_03_无效组合缺少弹性元件()
|
||||
Dim materials As Collection
|
||||
Set materials = New Collection
|
||||
|
||||
Dim mat1 As Object
|
||||
Set mat1 = CreateMaterial("接头", "接头A", "J001", 1)
|
||||
materials.Add mat1
|
||||
|
||||
Dim validation As Object
|
||||
Set validation = M08_ComponentProcessor.ValidateComponentCombination(materials)
|
||||
|
||||
Assert_Equal validation("valid"), False, "CP03_Invalid_No_Element"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 CP_04: 无效组合重复类型
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_CP_04_无效组合重复类型()
|
||||
Dim materials As Collection
|
||||
Set materials = New Collection
|
||||
|
||||
Dim mat1 As Object
|
||||
Set mat1 = CreateMaterial("部件", "部件A", "C001", 1)
|
||||
materials.Add mat1
|
||||
|
||||
Dim mat2 As Object
|
||||
Set mat2 = CreateMaterial("接头", "接头A", "J001", 1)
|
||||
materials.Add mat2
|
||||
|
||||
Dim validation As Object
|
||||
Set validation = M08_ComponentProcessor.ValidateComponentCombination(materials)
|
||||
|
||||
Assert_Equal validation("valid"), False, "CP04_Invalid_Both"
|
||||
End Sub
|
||||
|
||||
' ------------------------------------------------------------------------------
|
||||
' 测试用例 CP_05: 空物料列表验证
|
||||
' ------------------------------------------------------------------------------
|
||||
Private Sub Test_CP_05_空物料列表验证()
|
||||
Dim materials As Collection
|
||||
Set materials = New Collection
|
||||
|
||||
Dim validation As Object
|
||||
Set validation = M08_ComponentProcessor.ValidateComponentCombination(materials)
|
||||
|
||||
Assert_Equal validation("valid"), False, "CP05_Empty_List"
|
||||
End Sub
|
||||
|
||||
' ==============================================================================
|
||||
' 辅助函数
|
||||
' ==============================================================================
|
||||
|
||||
' 辅助断言函数
|
||||
Private Sub Assert_Equal(actual As Variant, expected As Variant, testName As String)
|
||||
If CStr(actual) = CStr(expected) Then
|
||||
m_PassCount = m_PassCount + 1
|
||||
Else
|
||||
Debug.Print " [FAIL] " & testName & " | Expected: " & expected & ", Actual: " & actual
|
||||
m_FailCount = m_FailCount + 1
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Assert_True(actual As Boolean, testName As String)
|
||||
If actual Then
|
||||
m_PassCount = m_PassCount + 1
|
||||
Else
|
||||
Debug.Print " [FAIL] " & testName & " | Expected: True, Actual: False"
|
||||
m_FailCount = m_FailCount + 1
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Assert_False(actual As Boolean, testName As String)
|
||||
If Not actual Then
|
||||
m_PassCount = m_PassCount + 1
|
||||
Else
|
||||
Debug.Print " [FAIL] " & testName & " | Expected: False, Actual: True"
|
||||
m_FailCount = m_FailCount + 1
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Assert_NotNull(obj As Object, testName As String)
|
||||
If Not obj Is Nothing Then
|
||||
m_PassCount = m_PassCount + 1
|
||||
Else
|
||||
Debug.Print " [FAIL] " & testName & " | Object is Nothing"
|
||||
m_FailCount = m_FailCount + 1
|
||||
End If
|
||||
End Sub
|
||||
|
||||
' 创建测试物料对象
|
||||
Private Function CreateMaterial( _
|
||||
ByVal matType As String, _
|
||||
ByVal matName As String, _
|
||||
ByVal matCode As String, _
|
||||
ByVal matQty As Long _
|
||||
) As Object
|
||||
Dim mat As Object
|
||||
Set mat = CreateObject("Scripting.Dictionary")
|
||||
mat("materialType") = matType
|
||||
mat("materialName") = matName
|
||||
mat("materialCode") = matCode
|
||||
mat("materialQty") = matQty
|
||||
mat("remarks") = ""
|
||||
Set CreateMaterial = mat
|
||||
End Function
|
||||
Reference in New Issue
Block a user