如何在 VB.NET 中为 TDD 伪造一个非常复杂的对象



假设我有一个名为CIRCLE的类,另一个名为SQUARE。在每个类中,我都有一个称为 area 的公共函数。(计算圆的面积和正方形的面积。

我还有一个iMath类。 在这个类中,我有一个函数ADD

    Public Function ADD(byval c as CIRCLE, byval s as SQUARE) 
       Return c.area() + s.area()
    End Function 

现在我想对 ADD 函数进行单元测试。显然,对于这个非常简单的问题,我可以轻松地创建一个圆形对象和一个方形对象来单元测试我的 ADD 函数。然而假设我的 Circle 对象和 Square 对象是非常复杂的对象,很难创建对象,因为它们继承并包含许多其他依赖项。在这种情况下,

  1. 如何伪造圆形和方形对象?(注意:CIRCLE 和 SQUARE 类没有任何参数的公共子新

  2. (
  3. 如何伪造面积函数 CIRCLE 和 SQUARE 对象的结果(我只需要一个数字来测试我的 ADD 函数,我不在乎面积是如何计算的(

如果将CIRCLE类的所有成员和SQUARE类都设为Overridable,则可以继承它们并用存根覆盖所有成员,例如:

Public Class Circle
    Public Overridable Function Area() As Integer
        ' Complicated logic
    End Function
End Class
Public Class MockCircle
    Inherits Circle
    Public Overrides Function Area() As Integer
        Return 10
    End Function
End Class

但是,如果原始CIRCLE类在其构造函数中需要一堆难以创建的参数,那么这对您没有任何帮助,因为仍然需要MockCircle类来调用基构造函数。

首选解决方案是使用接口。 与其让 ADD 方法接受具体的CIRCLE对象,不如让它请求实现ICircle接口的对象:

Public Interface ICircle
    Function Area() As Integer
End Interface
Public Class Circle
    Implements ICircle
    Public Function Area() As Integer Implements ICircle.Area
        ' Complicated logic
    End Function
End Class
Public Class MockCircle
    Implements ICircle
    Public Function Area() As Integer Implements ICircle.Area
        Return 10
    End Function
End Class
Public Class MyMath
    Public Function Add(c As ICircle, s As ISquare) As Integer
        Return c.Area() + s.Area()
    End Function
End Class

现在,CIRCLE在其构造函数中需要什么并不重要,因为您已经完全将其排除在等式之外。 现在,您可以为 ADD 方法提供一个CIRCLE对象或一个MockCircle对象,无论哪种方式,它都可以工作。 MockCircle对象不继承自CIRCLE,因此它不共享任何复杂的依赖关系。 这种方法实际上也有一个方便的名字。 它被称为依赖注入(DI(。 如果你要做大量的单元测试,那么花时间对DI做一些研究是非常值得的。 理想情况下,CIRCLE类的依赖项也将全部通过接口完成,因此您可以通过为其依赖项提供所有模拟对象来轻松创建CIRCLE对象。

我也觉得有义务提到你的代码的一些表面问题。 为了与 .NET 框架和Microsoft标准保持一致,您应该对所有方法和类名使用 PascalCase。 例如,它应该是Add而不是ADD,它应该是CircleSquare而不是CIRCLESQUARE。 此外,iMath类名不应以字母"i"开头。 根据Microsoft标准,在类型名称的开头放置"I"意味着它是一个接口,而不是一个类。 我看到的最后一个问题是您的ADD函数没有指定返回类型。 应始终指定所有函数的返回类型。 例如,在我的示例中,我将其更改为返回As Integer

你应该依靠现有的模拟框架,它正好解决了这个问题。我最喜欢的一个是NSubsitute。

它可以为任何具有虚函数的类接口创建模拟。一般来说,创建手动模拟更可取。

最新更新