【问题标题】:Expected error can only be a 440/Automation Error?预期错误只能是 440/自动化错误?
【发布时间】:2014-11-29 14:08:58
【问题描述】:

上下文

我在 VBA 中写了一点unit testing library,所以我可以像这样编写单元测试:

'@ExpectedError()
Public Sub TestCannotRegisterLoggerTwice()
    
    Dim logger As ILogger
    Set logger = MockLogger.Create("TestLogger", TraceLevel)
    
    LogManager.Register logger
    LogManager.Register logger
    
End Sub

以上测试通过:

2014-10-04 16:42:55 TestCannotRegisterLoggerTwice: [PASS]

如果我删除ExpectedError“属性”,它会失败:

2014-10-04 16:43:49 TestCannotRegisterLoggerTwice: [INCONCLUSIVE] - Test raised an error: Automation error

到目前为止,一切都很好。嗯,差不多。


测试中的错误可以正常工作!

现在如果我让测试抛出一个除以零,像这样:

'@ExpectedError()
Public Sub TestCannotRegisterLoggerTwice()
    
    Dim logger As ILogger
    Set logger = MockLogger.Create("TestLogger", TraceLevel)
    
    Dim boom As Integer
    boom = 1 / 0
    
    LogManager.Register logger
    LogManager.Register logger
    
End Sub

测试还没有定论,不过这次正确拾取错误:

2014-10-04 16:45:12 TestCannotRegisterLoggerTwice: [INCONCLUSIVE] - Test raised an error: Division by zero

我不明白的部分是,在这两种情况下,在同一个 VBAProject 中都会引发错误 - 前者在名为 LogManager(SUT)的类中,后者在一个名为LogManagerTests的类。

这是引发我正在测试的预期错误的部分:

Public Sub Register(ByVal logger As ILogger)
    If Not this.Loggers.Exists(logger.Name) Then
        this.Loggers.Add logger.Name, logger
    Else
        Err.Raise LogManagerError.DuplicateLoggerError, "LogManager.Register", "There is already a logger registered with name '" & logger.Name & "'."
    End If
End Sub

我想要什么

我希望能够用'@ExpectedError(-2147220406)LogManagerError.DuplicateLoggerErrorLong 表示)来装饰我的测试方法,并能够在TestEngine.ReflectTestMethods 方法中清理这部分:

For Each prospect In classMethods

    If CanAddTestMethod(prospect, result) Then
        
        Set tMethod = New TestMethod
        Set tMethod.OwnerInstance = classInstance
        tMethod.MethodName = prospect.name
        
        If prospect.HasAttribute(ExpectedErrorAttribute) Then
            If prospect.AttributeParameters(ExpectedErrorAttribute).Count <> 0 Then
                Err.Raise vbObjectError + 1055, "TestEngine.ReflectTestMethods", "ExpectedErrorAttribute for test method '" & prospect.name & "' should not have parameters."
            End If
            
            'force an "Automation Error" to be expected, 
            'because VBA "eats" the expected error thrown in the SUT:
            tMethod.ExpectedError = 440 ' prospect.AttributeParameters(ExpectedErrorAttribute).First
            
        End If
        
        result.Add tMethod.MethodName, tMethod
    
    End If

Next

是这样吗?我只能期望 SUT 抛出 自动化错误


我尝试过的东西

由于在实际测试方法中抛出错误时正确报错,所以我尝试了这个:

'@ExpectedError()
Public Sub TestCannotRegisterLoggerTwice()
    
    On Error GoTo CleanFail
    
    Dim logger As ILogger
    Set logger = MockLogger.Create("TestLogger", TraceLevel)
    
    LogManager.Register logger
    LogManager.Register logger
    
    Exit Sub
    
CleanFail:
    
    Dim errNumber As Long
    errNumber = Err.Number
    
    Dim errSource As String
    errSource = Err.Source
    
    Dim errDescription As String
    errDescription = Err.Description

    Err.Raise errNumber, errSource, errDescription
End Sub

但即使errDescription 包含正确/预期的错误消息,测试库仍会收到编号为 440 的 自动化错误


为什么我的测试库正确地选择了除以零,而不是自定义错误?

编辑:经过进一步的实验,我注意到我可以成功地“预期”任何内置错误,所以这是可行的:

'@ExpectedError(5)
Public Sub TestCannotRegisterLoggerTwice()
    
    Dim logger As ILogger
    Set logger = MockLogger.Create("TestLogger", TraceLevel)
    
    LogManager.Register logger
    LogManager.Register logger
    
End Sub

...前提是更改我的 TestEngine 代码以接受 @ExpectedError 属性的参数,并且我在 SUT 中引发错误 #5 /“无效的过程调用或参数”,而不是自定义错误;我也无法提供自定义错误消息。这并不理想,因为它会强制 SUT 只抛出内置错误,而我的测试库不能假设是这种情况。

VBA 中的自定义错误代码有什么特别之处?

【问题讨论】:

    标签: vba unit-testing error-handling


    【解决方案1】:

    我不知道 VBA 中的自定义错误代码有什么特别之处。

    但是,如果 SUT 中抛出的错误编号 不是 采用推荐的 vbObjectError + n 形式(可以从您期望的错误代码的 -2147220406 表示中推断出来) ,那么任何应用程序定义的或对象定义的错误都可以使用,并且“预期”:

    Public Enum LogManagerError
        DuplicateLoggerError = 100
        LoggerNotRegisteredError
    End Enum
    

    TestEngine 仍然不会“看到”自定义错误消息,但现在您可以这样做:

    '@ExpectedError(100)
    Public Sub TestCannotRegisterLoggerTwice()
    
        Dim logger As ILogger
        Set logger = MockLogger.Create("TestLogger", TraceLevel)
    
        LogManager.Register logger
        LogManager.Register logger
    
    End Sub
    

    得到这个结果:

    2014-10-04 18:09:56 TestCannotRegisterLoggerTwice: [PASS]
    

    如果ExpectedError 属性被删除,你会得到一个应用程序定义或对象定义的错误

    2014-10-04 18:10:20 TestCannotRegisterLoggerTwice: [INCONCLUSIVE] - Test raised an error: Application-defined or object-defined error
    

    这在技术上是正确的——当然,能够在测试结果中报告自定义错误消息会很好,但这只是必须处理的限制之一。

    至少您现在可以在 SUT 中抛出不同的错误,并且能够判断是否引发了那个错误 - 这是这里要实现的目标。

    同时自定义错误消息在“正常”代码中仍然可见和可显示:

    '@ExpectedError(100)
    Public Sub TestCannotRegisterLoggerTwice()
    
        On Error GoTo CleanFail
    
        Dim logger As ILogger
        Set logger = MockLogger.Create("TestLogger", TraceLevel)
    
        LogManager.Register logger
        LogManager.Register logger
    
        Exit Sub
    CleanFail:
        MsgBox Err.Description
        Err.Raise Err.Number
    
    End Sub
    

    2014-10-04 18:21:24 TestCannotRegisterLoggerTwice: [PASS]
    

    【讨论】:

      猜你喜欢
      • 2014-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-08
      • 2011-11-24
      相关资源
      最近更新 更多