除了使测试更容易之外,封闭系统中的接口有什么优势?

时间:2017-09-08 10:03:55

标签: c# unit-testing interface mocking

我需要模拟某些类才能测试我软件的某些部分。但我当然可以只使用界面来模拟它们。例如,如果我有这样的东西(使用Moq):

    [TestMethod]
    public void AddTestTaskTest()
    {
        TestTask assignable = null;
        var contextMock = new Mock<ApplicationDatabaseContext>();
        var appDbAdaptorMock = new Mock<ApplicationDatabaseAdaptor>(contextMock.Object);

        var dbOpMock = new Mock<TestTaskDbOperator>();

        void Action(TestTask t) => assignable = t;
        dbOpMock.Setup(p => p.Add(It.IsAny<TestTask>())).Callback<TestTask>(Action);
        appDbAdaptorMock.Setup(d => d.TestTasks).Returns(dbOpMock.Object);

        var db = new ApplicationDatabaseController(appDbAdaptorMock.Object);
        var task = CreateTestTaskObject(1);
        db.AddTestTask(task);
        Assert.AreEqual(task, assignable);
    }

(测试还没有多少意义,但是关于原理)

然后我显然必须创建一个接口IApplicationDatabaseAdaptor,以便我可以用mock覆盖属性和方法。我已经看到很多建议在SO和其他地方的其他地方这样做,理由是它能够实现解耦。

“启用解耦”是什么意思?为什么这么多人鼓励使用这样的接口?为什么创建这样的接口不被认为是不好的做法?特别是如果我知道我只会使用它们进行嘲弄,而不是其他任何东西。

2 个答案:

答案 0 :(得分:1)

当一个类需要另一个类时,类会“耦合”。因此,当您在界面中声明只有一个“知道”另一个。主要目标是使所有类在整个应用程序中“尽可能松散”。它使您的代码更易于维护,并使我们的应用程序中的代码更容易,更安全。

但是我们可以想到使用接口的另一个好例子: 您正在编写的图像和使用Web服务保存其数据的应用程序。现在,客户希望脱机工作,因为他在使用应用程序时无法访问互联网,但后来又在办公室工作时。

如果你“隐藏”与接口后面的数据库的通信,现在很容易为你编写一个新的接口实现来与本地数据库通信而你不必重写任何代码:只需创建另一个实现接口和使用它。

另一个例子是当你使用接口时,就像你一样,可以模拟数据。图像中有一个DatabaseProvider,它从数据库中读取数据。现在你有一个类用这些数据做一些事情,你想测试你的类是否正常工作。你会怎么做?

在测试类中,您可以模拟来自数据库的数据,让您的类使用它来实现其魔力。这只是使用接口进行数据访问的一大优势。

答案 1 :(得分:1)

任何未封装的东西都应该定义和界面,原因如下。

  1. 通过创建模拟来使用该类对代码进行单元测试。
  2. 对于测试驱动开发,您通常会定义子组件的接口。
  3. 界面隔离。
  4. 如果你不想要任何这些,那么继续你可以使用NSubstitute,这将允许你模拟具体的类。

    现实世界场景中的解耦意味着

    1. 您可以通过模拟来延迟组件的具体实现 接口。
    2. 您可以切换实现,而无需在更改的实现之外触及代码。