针对类的NSubstitute测试(VB.net)

时间:2014-04-30 08:57:35

标签: vb.net unit-testing nsubstitute

首先,我是单元测试的初学者。对于我的测试,我想使用NSubstitute,所以我阅读了网站上的教程以及Richard Banks的模拟比较。它们都是针对接口而不是针对类进行测试。声明是“通常这个[替换]类型将是一个接口,但您也可以在紧急的情况下替换类。”

现在我想知道测试接口的目的。以下是NSubstitute网站的示例界面(请注意,我已经在VB.net中转换了C#代码):

Public Interface ICalculator
    Function Add(a As Double, b As Double) As Double
    Property Mode As String
    Event PoweringUp As EventHandler
End Interface

以下是网站上的单元测试(在NUnit-Framework下):

<Test>
Sub ReturnValue_For_Methods()

    Dim calculator = Substitute.For(Of ICalculator)()
    calculator.Add(1, 2).Returns(3)

    Assert.AreEqual(calculator.Add(1, 2), 3)

End Sub

好的,这样可行,单元测试也会成功。但这有什么意义呢?这不会测试任何代码。 添加 -Method可能有任何错误,在测试接口时将无法检测到 - 如下所示:

Public Class Calculator
    Implements ICalculator

    Public Function Add(a As Double, b As Double) As Double Implements ICalculator.Add
        Return 1 / 0
    End Function

    ...

End Class

添加 -Method执行除零,因此单元测试应该失败 - 但是由于对ICalculator接口的测试,测试成功。

你可以帮我理解一下吗?有什么意义呢,不是测试代码而是测试界面?

提前致谢 迈克尔

1 个答案:

答案 0 :(得分:0)

模拟背后的想法是将我们正在测试的类与其依赖关系隔离开来。因此,我们不会模拟我们正在测试的类,在这种情况下Calculator,我们在测试使用ICalculator的类时模拟ICalculator

一个小例子是我们想要测试某些东西与数据库的交互方式,但我们不想使用真正的数据库进行一些快速测试。 (请原谅C#。)

[Test]
public void SaveTodoItemToDatabase() {
  var substituteDb = Substitute.For<IDatabase>();
  var todoScreen = new TodoViewModel(substituteDb);

  todoScreen.Item = "Read StackOverflow";
  todoScreen.CurrentUser = "Anna";
  todoScreen.Save();

  substituteDb.Received().SaveTodo("Read StackOverflow", "Anna");
}

这里的想法是我们将TodoViewModel与保存到数据库的细节分开。我们不想担心配置数据库,获取连接字符串,或者让先前测试运行的数据干扰未来的测试运行。使用真实数据库进行测试非常有价值,但在某些情况下,我们只想测试较小的功能单元。模拟是这样做的一种方式。

对于真实应用,我们将创建一个TodoViewModel,其实际实现为IDatabase,并且假设该实现遵循预期的接口合同,那么我们可以合理地期望它会起作用。

希望这有帮助。


更新以回复comment

TodoViewModel的测试假定IDatabase的实施有效,因此我们可以专注于该课程&#39;逻辑。这意味着我们可能需要一组单独的测试来实现IDatabase。假设我们有一个SqlServerDb实现,那么我们可以进行一些测试(可能针对一个真正的数据库),检查它是否符合它的承诺。在那些测试中,我们不再嘲笑数据库界面,因为这是我们正在测试的内容。

我们可以做的另一件事是进行合同测试&#34;我们可以将其应用于任何IDatabase实施。例如,我们可以进行测试,对于任何实现,保存项目然后再次加载应该返回相同的项目。然后,我们可以针对所有实现运行这些测试,SqlDbInMemoryDbFileDb等。这样我们可以陈述我们对我们正在嘲笑的依赖关系的假设,然后检查实际的实现符合我们的假设。