RubberDuck可以测试程序是否结束吗?

时间:2018-12-25 22:55:29

标签: vba rubberduck

我正在用RubberDuck开发测试,并且想测试程序中的MsgBox输出。问题是程序在输出MsgBox之后立即结束-字面上是一个“ End”语句。

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

我尝试在测试结束时放置“ Assert.Fail”;但是,似乎程序结尾会使事情变得毫无意义。

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

1 个答案:

答案 0 :(得分: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

细分:

这将创建一个托管类,用于“监听”正在测试的代码中的Asserts,并评估通过或未通过测试的条件。

Private Assert As New Rubberduck.AssertClass     

FakesProvider是一个实用程序对象,用于将VB运行时中的钩子设置为从VB运行时内部对InputBox函数的“忽略”或“欺骗”调用。

由于Fakes对象被声明为As New,因此With块实例化了一个FakesProvider来进行测试。 InputBox的{​​{1}}方法在vbe7.dll中的Fakes函数上设置了一个钩子,该钩子将所有从VBA到该函数的流量重定向到Rubberduck实现。现在,它可以计算呼叫次数,跟踪传递的参数,提供返回值等。

rtcInputBox

“返回”和“返回时”调用使用VBA保留的COM对象将伪造调用的测试设置传送到 With Fakes.InputBox 。在此示例中,它配置InputBox对象以返回呼叫1的InputBox,并为呼叫二传递vbNullString的{​​{1}}参数时返回“用户条目2”

Prompt

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

IsTrue

这与您的问题有关意味着什么:

请注意,在上述代码的执行方式明细中, 所有内容均在VBA环境中执行 。 Rubberduck正在为VBA提供“窗口”,以通过AssertClass对象报告结果,并简单地(对于“ simply”的某些值)通过 Assert.IsTrue userInput = vbNullString 对象提供挂钩服务。 VBA“拥有”这两个对象-它们只是通过Rubberduck的COM提供程序提供的。

在VBA中使用End语句时,它会在此时强制终止执行。客户端不再主动引用Rubberduck COM对象(您的测试过程),并且不确定是否会减少COM对象上的引用计数。就像将插头从墙上拉出一样。此时,Rubberduck唯一可以确定的是COM客户端已断开连接。在您的情况下,这表明是Rubberduck中捕获的COM异常。由于Rubberduck无法得知为什么提供的对象失去了通信,因此它会将测试结果报告为“不确定”-尚未运行完毕。


也就是说,解决方案是重构代码以不使用AssertClass。曾经引用上方FakesProvider ...

链接的文档
  

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

这远远不能令人满意,如果您引用了其他COM对象(Rubberduck除外),则不能保证它们将可靠地终止。


完全公开,我参与了Rubberduck项目,并编写了上述一些代码。如果您想更好地了解单元测试的功能(并可以阅读c#),请使用COM提供程序can be found at this link的实现。