我正在尝试编写一个可以让我为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
答案 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项目和存储库。