1。编写可测试的代码
首先,停止将业务逻辑写入您的表单代码中。那不是它的地方。它无法在那里正确测试。事实上,你真的不应该测试你的表单本身。它应该是一个非常愚蠢的简单视图,它响应用户交互,然后将响应这些操作的责任委托给另一个可测试的类。
你是怎么做到的?熟悉Model-View-Controller pattern 是一个好的开始。
这在 VBA 中无法完美地完成,因为我们获得了事件或接口,而不是两者,但您可以非常接近。考虑一下这个简单的表单,它有一个文本框和一个按钮。
在后面的表单代码中,我们将 TextBox 的值包装在一个公共属性中,并重新引发我们感兴趣的任何事件。
Public Event OnSayHello()
Public Event AfterTextUpdate()
Public Property Let Text(value As String)
Me.TextBox1.value = value
End Property
Public Property Get Text() As String
Text = Me.TextBox1.value
End Property
Private Sub SayHello_Click()
RaiseEvent OnSayHello
End Sub
Private Sub TextBox1_AfterUpdate()
RaiseEvent AfterTextUpdate
End Sub
现在我们需要一个模型来使用。在这里,我创建了一个名为MyModel 的新类模块。这是我们将要测试的代码。请注意,它自然与我们的视图具有相似的结构。
Private mText As String
Public Property Let Text(value As String)
mText = value
End Property
Public Property Get Text() As String
Text = mText
End Property
Public Function Reversed() As String
Dim result As String
Dim length As Long
length = Len(mText)
Dim i As Long
For i = 0 To length - 1
result = result + Mid(mText, (length - i), 1)
Next i
Reversed = result
End Function
Public Sub SayHello()
MsgBox Reversed()
End Sub
最后,我们的控制器将它们连接在一起。控制器侦听表单事件并将更改传达给模型并触发模型的例程。
Private WithEvents view As Form_Form1
Private model As MyModel
Public Sub Run()
Set model = New MyModel
Set view = New Form_Form1
view.Visible = True
End Sub
Private Sub view_AfterTextUpdate()
model.Text = view.Text
End Sub
Private Sub view_OnSayHello()
model.SayHello
view.Text = model.Reversed()
End Sub
现在可以从任何其他模块运行此代码。出于本示例的目的,我使用了标准模块。我强烈建议您使用我提供的代码自己构建它并查看它的功能。
Private controller As FormController
Public Sub Run()
Set controller = New FormController
controller.Run
End Sub
所以,这很好,所有但它与测试有什么关系?!朋友,它有一切 与测试有关。我们所做的是让我们的代码可测试。在我提供的示例中,甚至没有理由尝试测试 GUI。我们唯一真正需要测试的是model。这就是所有真正的逻辑所在。
那么,进入第二步。
2。选择单元测试框架
这里没有很多选择。大多数框架都需要安装 COM 插件、大量样板、奇怪的语法、将测试编写为 cmets 等。这就是我参与building one myself 的原因,所以我的这部分答案并不公正,但我会尝试对可用的内容进行公平的总结。
-
AccUnit
- 仅适用于 Access。
- 要求您将测试编写为 cmets 和代码的奇怪混合体。 (评论部分没有智能感知。
-
有一个图形界面可以帮助您编写那些看起来很奇怪的测试。
- 该项目自 2013 年以来没有任何更新。
VB Lite Unit
我不能说我个人使用过它。它在那里,但自 2005 年以来没有看到更新。
xlUnit
xlUnit 并不糟糕,但也不是很好。它很笨重,并且有很多样板代码。这是最好的,最坏的,但它在 Access 中不起作用。所以,这就结束了。
-
构建你自己的框架
我有been there and done that。它可能比大多数人想要的要多,但完全可以用原生 VBA 代码构建单元测试框架。
-
Rubberduck VBE Add-In's Unit Testing Framework
免责声明:我是共同开发者之一。
我有偏见,但这是迄今为止我最喜欢的。
- 几乎没有样板代码。
- Intellisense 可用。
- 项目处于活动状态。
- 比大多数这些项目更多的文档。
- 它适用于大多数主要的办公应用程序,而不仅仅是 Access。
- 很遗憾,它是一个 COM 插件,因此必须将其安装到您的计算机上。
3。开始编写测试
所以,回到第 1 节中的代码。我们真正需要测试的唯一代码是 MyModel.Reversed() 函数。那么,让我们来看看这个测试会是什么样子。 (给出的示例使用 Rubberduck,但它是一个简单的测试,可以转化为您选择的框架。)
'@TestModule
Private Assert As New Rubberduck.AssertClass
'@TestMethod
Public Sub ReversedReversesCorrectly()
Arrange:
Dim model As New MyModel
Const original As String = "Hello"
Const expected As String = "olleH"
Dim actual As String
model.Text = original
Act:
actual = model.Reversed
Assert:
Assert.AreEqual expected, actual
End Sub
编写良好测试的指南
- 一次只测试一件事。
- 只有在系统引入错误或需求发生变化时,良好的测试才会失败。
- 不要包含外部依赖项,例如数据库和文件系统。这些外部依赖项会使测试因您无法控制的原因而失败。其次,它们会减慢您的测试速度。如果你的测试很慢,你就不会运行它们。
- 使用描述测试所测试内容的测试名称。如果它变长,请不要担心。最重要的是它具有描述性。
我知道这个答案有点长而且晚了,但希望它可以帮助一些人开始为他们的 VBA 代码编写单元测试。