由于代码、表单和数据都在同一个数据库中,我想知道为Microsoft Access应用程序(比如Access 2007)设计一套测试的最佳实践是什么。
测试窗体的主要问题之一是,只有少数控件具有hwnd句柄,而其他控件只有一个拥有焦点的控件,这使得自动化非常不透明,因为您无法获得窗体上可操作的控件列表。
有什么经验可以分享吗?
发布于 2015-02-05 22:50:44
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插件、大量模板、奇怪的语法、编写测试作为注释等等。这就是我参与building one myself的原因,所以我的这部分回答并不公正,但我会尝试对可用的内容给出一个公平的总结。
- Works only in Access.
- Requires you to write tests as a strange hybrid of comments and code. (no intellisense for the comment part.
- There _**is**_ a graphical interface to help you write those strange looking tests though.
- The project has not seen any updates since 2013.
我已经been there and done that了。它可能比大多数人想要的要多,但是在Native VBA code.
免责声明:我是联合开发者之一。
我有偏见,但到目前为止,这是我最喜欢的。
- Little to no boiler plate code.
- Intellisense is available.
- The project is active.
- More documentation than most of these projects.
- It works in most of the major office applications, not just Access.
- It is, unfortunately, a COM Add-In, so it has to be installed onto your machine.
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代码编写单元测试。
发布于 2008-09-16 09:07:31
我很欣赏诺克斯和大卫的回答。我的答案介于他们的答案之间:让不需要调试的表单成为!
我认为窗体应该完全按照它们原来的样子来使用,这意味着图形界面,这意味着它们不需要调试!然后,调试作业仅限于您的VBA模块和对象,处理起来容易得多。
当然,向窗体和/或控件添加VBA代码是一种自然的趋势,特别是当Access为您提供了这些伟大的“更新后”和“更改时”事件时,但我强烈建议您不要使用将任何窗体或控件特定的代码放入窗体的模块中。这使得进一步的维护和升级成本非常高,您的代码将在VBA模块和窗体/控件模块之间拆分。
这并不意味着您不能再使用此AfterUpdate事件!只需在事件中放入标准代码,如下所示:
Private Sub myControl_AfterUpdate()
CTLAfterUpdate myControl
On Error Resume Next
Eval ("CTLAfterUpdate_MyForm()")
On Error GoTo 0
End sub其中:
CTLAfterUpdate是每次更新控件时运行的标准过程formCTLAfterUpdateMyForm是每次在MyForm上更新控件时运行的特定过程
然后我有2个模块。第一个是
utilityFormEvents我将在何处安装CTLAfterUpdate generic event
第二个是
MyAppFormEvents包含MyApp应用程序的所有特定形式的特定代码,并包括CTLAfterUpdateMyForm过程。当然,如果没有要运行的特定代码,CTLAfterUpdateMyForm可能就不存在。这就是为什么我们将"On error“改为"resume next”...
选择这样的通用解决方案意义重大。这意味着你正在达到一个高水平的代码规范化(意味着代码的无痛苦维护)。当您说您没有任何特定于表单的代码时,这也意味着表单模块是完全标准化的,它们的生产可以是automated:只需说明您希望在表单/控件级别管理哪些事件,并定义您的通用/特定过程术语。
写你的自动化代码,一劳永逸。
它需要几天的工作,但它给出了令人兴奋的结果。我在过去的两年里一直在使用这个解决方案,它显然是正确的:我的表单是完全自动从头开始创建的,有一个"Forms Table",链接到一个"Controls Table“。
然后,我可以将时间花在表单的具体过程上。
代码规范化,即使使用MS Access,也是一个漫长的过程。但是这样的痛苦是值得的!
发布于 2008-09-16 16:45:37
Access being a COM application的另一个优点是您可以创建一个.NET application to run and test an Access application via Automation。这样做的好处是,您可以使用更强大的测试框架(如NUnit )来编写针对访问应用程序的自动化断言测试。
因此,如果你精通C#或VB.NET,再加上NUnit之类的东西,那么你就可以更容易地为你的访问应用程序创建更大的测试覆盖率。
https://stackoverflow.com/questions/47400
复制相似问题