我正在使用RubberDuck开发测试,并希望从程序中测试MsgBox输出.问题在于程序在输出MsgBox后立即结束 - 实际上是一个"结束"语句.
当运行RubberDuck测试并使用Fakes.MsgBox.Returns时,会出现一个不确定的黄色结果,并显示消息"运行测试时出现意外的COM异常"
我试过在测试结束时放置一个"Assert.Fail"; 然而,似乎程序结束会引发争议.
RubberDuck中的测试是否可以检测程序是否结束?
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,因此该With块FakesProvider为测试实例化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提供程序的实现.