如果程序结束,RubberDuck可以测试吗?

use*_*114 4 vba rubberduck

我正在使用RubberDuck开发测试,并希望从程序中测试MsgBox输出.问题在于程序在输出MsgBox后立即结束 - 实际上是一个"结束"语句.

当运行RubberDuck测试并使用Fakes.MsgBox.Returns时,会出现一个不确定的黄色结果,并显示消息"运行测试时出现意外的COM异常"

我试过在测试结束时放置一个"Assert.Fail"; 然而,似乎程序结束会引发争议.

RubberDuck中的测试是否可以检测程序是否结束?

Com*_*ern 6

tldr; 没有

Rubberduck单元测试在VBA运行时的上下文中执行 - 也就是说,VBA单元测试代码是从主机应用程序内部运行的.测试结果通过其API报告给Rubberduck.如果查看插入测试模块时生成的VBA代码,它可以基本了解测试运行的体系结构.以我们的集成测试套件中的单元测试为例:

'HERE BE DRAGONS.  Save your work in ALL open windows.
'@TestModule
'@Folder("Tests")

Private Assert As New Rubberduck.AssertClass
Private Fakes As New Rubberduck.FakesProvider

'@TestMethod
Public Sub InputBoxFakeWorks()
    On Error GoTo TestFail

    Dim userInput As String
    With Fakes.InputBox
        .Returns vbNullString, 1
        .ReturnsWhen "Prompt", "Second", "User entry 2", 2
        userInput = InputBox("First")
        Assert.IsTrue userInput = vbNullString
        userInput = InputBox("Second")
        Assert.IsTrue userInput = "User entry 2"
    End With

TestExit:
    Exit Sub
TestFail:
    Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
End Sub
Run Code Online (Sandbox Code Playgroud)

细分:

这将创建一个托管类,该类在被测试的代码中"侦听"Asserts,并评估传递或未通过测试的条件.

Private Assert As New Rubberduck.AssertClass     
Run Code Online (Sandbox Code Playgroud)

FakesProvider是一个实用程序对象,用于将VB运行时中的挂钩设置为"忽略"或"欺骗"从VB运行时内部调用到该InputBox函数.

由于Fakes声明了对象As New,因此该WithFakesProvider为测试实例化a .该InputBox方法Fakes这将设置在一个钩子rtcInputBox在vbe7.dll功能,从VBA的所有流量重定向到功能到Rubberduck实施.现在计算调用,跟踪传递的参数,提供返回值等.

    With Fakes.InputBox
Run Code Online (Sandbox Code Playgroud)

返回和返回当调用使用VBA持有的COM对象来传递伪造调用的测试设置时InputBox.在此示例中,它将InputBox对象配置为返回一个vbNullStringfor call,并在传递一个第二个call 的Prompt参数时"User entry 2" "Second".

        .Returns vbNullString, 1
        .ReturnsWhen "Prompt", "Second", "User entry 2", 2
Run Code Online (Sandbox Code Playgroud)

这就是AssertClass的用武之地.当您从Rubberduck UI运行单元测试时,它会确定用户代码的COM接口.然后,它调用通过该接口调用测试方法.然后Rubberduck使用它AssertClass来测试运行时条件.该IsTrue方法将a Boolean作为参数(带有可选的输出消息).因此,在下面的代码行中,VB计算表达式userInput = vbNullString并将结果作为参数传递给IsTrue.然后,Rubberduck IsTrue实现根据从VBA传递的参数是否满足所AssertClass调用方法的条件来设置单元测试的状态.

        Assert.IsTrue userInput = vbNullString
Run Code Online (Sandbox Code Playgroud)

这对您的问题意味着什么:

请注意,在上面的代码执行方式细分中,所有内容都在VBA环境中执行.Rubberduck为VBA提供了一个"窗口",通过AssertClass对象报告结果,并简单地(对于"简单"的某些值)通过FakesProvider对象提供钩子服务.VBA"拥有"这两个对象 - 它们只是通过Rubberduck的COM提供程序提供的.

End在VBA中使用该语句时,它会强制终止该点的执行.客户端(您的测试过程)不再主动引用Rubberduck COM对象,并且未定义是否减少COM对象上的引用计数.就像从墙上拔下插头一样.此时Rubberduck唯一可以确定的是COM客户端已断开连接.在你的情况下,表现为在Rubberduck内部捕获的COM异常.由于Rubberduck无法知道它所提供的对象为什么会丢失通信,因此它将测试结果报告为"不确定" - 它没有完成.


也就是说,解决方案是重构您的代码以免使用End.永远.引用上面链接的文档End......

立即终止执行.从不需要,但可以放在过程中的任何位置来结束代码执行,关闭使用Open语句打开的文件,以及清除变量.

这远远不是优雅的,如果您引用其他COM对象(除了Rubberduck),则无法保证它们将被可靠地终止.


完全披露,我参与了Rubberduck项目,并撰写了上述的一些代码.如果您想更好地了解单元测试的功能(并且可以读取c#),可以在此链接中找到 COM提供程序的实现.

  • TL; DR:不要使用`End`,除非你唯一的选择是拔出插件并核实运行时环境. (4认同)