我正在用RubberDuck开发测试,并且想测试程序中的MsgBox输出。问题是程序在输出MsgBox之后立即结束-字面上是一个“ End”语句。
运行RubberDuck测试并使用Fakes.MsgBox.Returns时,会出现黄色的不确定结果,并显示消息“运行测试时出现意外的COM异常”
我尝试在测试结束时放置“ Assert.Fail”;但是,似乎程序结尾会使事情变得毫无意义。
RubberDuck中的测试是否可以检测程序是否结束?
答案 0 :(得分:6)
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的实现。