编写VBA单元测试套件

时间:2015-09-30 13:55:22

标签: vba unit-testing

我正在尝试编写一个可以让我为VBA编写单元测试的插件。我有一个用于测试断言的类设置等。我缺少的是一种存根/模拟类的方法有没有办法做到这一点?

为了澄清我正在谈论实例化假装属于不同类的对象。例如,我想写一个Person类将使用的Address类的模拟:

人类

int index = 0;
DataTable results = GetCounters();
//results has two rows: [CounterSales] & [CounterBlah5]

foreach (DataRow row in results.Rows)
{
    string counter = cellRow["counter"]; //counter equals "CounterSales"
    /* Iterate through all <ns> to see where "CounterSales" is located.
       In this case, index = 2. On next foreach, index equals 4  */

    var xDoc = XDocument.Parse(xmlStr);
    var nvs = xDoc.Descendants("nv");
    var nads = nvs.Select(nv => nv.Elements("nad").First().Value).ToList();
    var thirdRs = nvs.Select(nv => nv.Elements("r").ElementAt(index).Value).ToList();
}

地址类

 Private Home as Address

 Sub ChangeAddress(NewStreetAddress as String)
      Address.Street = NewStreetAddress
 end Sub

1 个答案:

答案 0 :(得分:2)

可测试的,面向对象的VBA代码,可以让您控制依赖项,必须针对抽象编写。 Code Review Stack Exchange上的Extensible logging就是一个很好的例子。

简而言之,您的代码需要依赖于 interfaces - 只有这样,您的单元测试才能通过“假”实现。从链接的CR帖子中获取ILogger类模块:

Option Explicit

Public Sub Log(ByVal output As String)
End Sub

Public Property Get Name() As String
End Property

Public Property Get MinLevel() As LogLevel
End Property

那是界面。一个实现称为DebugLogger,如下所示 - 注意实现ILogger

Option Explicit

Private Type TDebugLogger
    Name As String
    MinLevel As LogLevel
End Type
Private this As TDebugLogger

Implements ILogger

Public Function Create(ByVal loggerName As String, ByVal loggerMinLevel As LogLevel) As ILogger

    Dim result As New DebugLogger
    result.Name = loggerName
    result.MinLevel = loggerMinLevel
    Set Create = result

End Function

Friend Property Get Name() As String
    Name = this.Name
End Property

Friend Property Let Name(ByVal value As String)
    this.Name = value
End Property

Friend Property Get MinLevel() As LogLevel
    MinLevel = this.MinLevel
End Property

Friend Property Let MinLevel(ByVal value As LogLevel)
    this.MinLevel = value
End Property

Private Sub ILogger_Log(ByVal output As String)
    Debug.Print output
End Sub

Private Property Get ILogger_MinLevel() As LogLevel
    ILogger_MinLevel = this.MinLevel
End Property

Private Property Get ILogger_Name() As String
    ILogger_Name = this.Name
End Property

现在,如果你有使用ILogger的代码,你的单元测试可以传入一个实现,它不会向控制台打印内容,而是引发一个事件,报告正在记录的消息以及在什么级别:您的测试模块可以处理这些事件,设置模块级标志,[假设您已经实现了Assert类,或者您正在使用Rubberduck单元测试],然后可以调用{{1}验证标志。或者其他什么。

最重要的是,它可以完成:我有一个Assert.IsTrue接口,实现命中数据库,我的单元测试使用“假”实现,实际上只包裹IRepository

至于 mocking ,就像在中生成一个实现,然后注入那个......,这不是一件容易的事情,但我可以看到Rubberduck在未来的版本中提供类似的东西。

  

免责声明 - 我共同拥有Rubberduck项目和存储库。