【问题标题】:When to use stubs and mocks?何时使用存根和模拟?
【发布时间】:2010-11-20 06:21:05
【问题描述】:

我一直有这种困惑。如果我编写了一个使用假代码来断言某些操作的代码,当我真正开始使用真实对象而不是假对象时,我如何相信我的真实实现。

例如,我有这个代码--

    [Test]
    public void CanCreateContactsWithData()
    {
        using(ISession session = factory.OpenSession())
        using (ITransaction trans = session.BeginTransaction())
        {
            _contactId = (long) session.Save(contact);
            trans.Commit();
        }

        Assert.AreNotEqual(0, _contactId);
    }

此代码测试“联系人”对象的实现,无论该对象是否保存到数据库中。如果我碰巧使用存根而不是真正的数据库连接,是否需要单独测试将其存储在数据库中?而且,你们称之为集成测试吗?

非常感谢您的回答。

【问题讨论】:

    标签: unit-testing mocking stubbing


    【解决方案1】:

    Martin Fowler 进行了很好的讨论here

    来自他的文章:

    Meszaros 使用术语 Test Double 作为通用术语,用于代替真实对象用于测试目的的任何类型的假装对象。这个名字来源于电影中特技替身的概念。 (他的目标之一是避免使用任何已经被广泛使用的名称。)Meszaros 然后定义了四种特殊类型的双精度:

    • 虚拟对象被传递,但从未实际使用。通常它们只是用来填充参数列表。
    • 假对象实际上有工作实现,但通常采取一些捷径,使它们不适合生产(内存数据库就是一个很好的例子)。
    • 存根对测试期间的呼叫提供预设答案,通常根本不响应任何超出测试编程的内容。存根还可以记录有关呼叫的信息,例如记住它“发送”的消息的电子邮件网关存根,或者可能只记录它“发送”的消息的数量。
    • Mocks 就是我们在此讨论的内容:预编程了期望的对象,这些期望构成了它们期望接收的调用的规范。

    在这些类型的替身中,只有模拟坚持行为验证。

    【讨论】:

      【解决方案2】:

      当您只想让函数返回某个值(或什么都不做)时,您可以使用存根。你并不关心函数是否被调用,你只想隔离事物。

      Mocks 更强大,因为您还可以跟踪函数是否被调用、调用了多少次,甚至可以使用函数获取的值进行操作。

      在您的情况下,如果您想模拟数据库(使其成为单元测试而不是功能测试),您可以模拟 ISession 和 ITransaction。然后,您可以将此值存储在内存中,并检查是否保存了正确的值。

      【讨论】:

        【解决方案3】:

        您应该测试您编写的代码。如果您编写了数据库连接对象代码,则对其进行测试。否则,如果它是带有自己测试的库的一部分,您可以模拟/存根它并假设如果连接对象通过了它自己的测试套件,那么它就可以工作。

        例如,我不会测试对 Hibernate 方法的调用,我假设 Hibernate 开发人员已经对此进行了彻底的测试。但我测试我是否调用了正确的方法,使用模拟来设置该期望。

        【讨论】:

          【解决方案4】:

          是的,根据您的定义,使用真实的数据库会进行更多功能或集成测试。就个人而言,我认为单元测试应该只测试该方法,与其他一切隔离。因此,无论会话或事务是否有效,您的单元测试都必须确保在必要时调用这些对象 来完成它们的工作——这就是模拟和存根出现的地方。你使用它们来确保您的单元测试与外部功能分离,以便可以将其作为基本单元进行测试;无论如何都是理想的。

          【讨论】:

          • 能否用一些例子来详细说明你的答案.. 提前致谢
          • 答案很长,但请查看mockobjects.com/book(为插件道歉)。
          【解决方案5】:

          大多数类型的单元测试都是关于测试单个代码段,而存根和模拟只是帮助您逐段测试的工具。通过单独测试各个部分,您可能可以更详细地测试每个部分,但您无法得到关于全貌的任何保证。各种集成测试都可以做到这一点。

          在测试更大的功能时,我经常发现数据库逻辑的实际集成测试是最没有价值的测试工件,因为您通常会在 UI 级别测试这些相同的操作。

          【讨论】:

            猜你喜欢
            • 2011-07-07
            • 2017-02-14
            • 2010-10-29
            • 1970-01-01
            • 2018-07-10
            • 2011-08-12
            • 2013-10-04
            • 2015-12-17
            • 1970-01-01
            相关资源
            最近更新 更多