首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >mocks比stub更好吗?

mocks比stub更好吗?
EN

Stack Overflow用户
提问于 2008-09-06 19:13:08
回答 6查看 1.7K关注 0票数 14

不久前,我读到了Martin Fowler的Mocks Aren't Stubs文章,我必须承认,关于增加的复杂性,我有点害怕外部依赖,所以我想问一下:

在进行单元测试时最好的方法是什么?

总是使用模拟框架来自动模拟被测试方法的依赖关系更好,还是更喜欢使用更简单的机制,例如测试存根?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2008-09-06 20:00:24

正如这句口头语所说:“做最简单的事情,只要可能行得通。”

  1. 如果虚构的类可以完成任务,那就使用它们。
  2. 如果您需要一个包含多个要模拟的方法的接口,请使用模拟框架。

避免总是使用mock,因为它们会使测试变得脆弱。如果被模拟的接口或您的实现发生变化,您的测试现在对由实现调用的方法有了复杂的了解。你的测试失败了。这是不好的,因为你会花费额外的时间让你的测试运行,而不仅仅是让你的SUT运行。测试不应该与实现不适当地密切相关。

所以用你最好的判断力..我更喜欢模拟,因为它可以帮助我省去编写代码--用n>>3方法更新一个假的类。

更新前言/讨论:

(多亏了Toran Billups,例如一个mockist测试。见下文)

嗨,道格,我想我们已经进入了另一场圣战-经典TDDers vs模拟人TDDers。我想我属于前者。

  • 如果我在test#101 Test_ExportProductList上,我发现我需要向IProductService.GetProducts()添加一个新的参数。我这样做是为了让这个测试变绿。我使用重构工具来更新所有其他引用。现在我发现所有调用这个成员的mockist测试都失败了。然后我不得不回去更新所有这些测试--这是浪费时间。为什么会失败?是因为代码被破坏了吗?更确切地说,测试是失败的。我倾向于一个测试失败=一个需要修复的地方。嘲笑freq与此背道而驰。存根会更好吗?如果我有一个fake_class.GetProducts()..当然,只有一个地方可以改变,而不是在多个Expect调用上进行鸟枪操作。归根结底,这是一个风格问题。如果您有一个通用的实用程序方法MockHelper.SetupExpectForGetProducts() -那也足够了。但是你会发现这是不常见的。
  • 如果您在测试名称上放置一个白条,测试将很难阅读。许多模拟框架的管道代码隐藏了实际的测试,以便您了解这种特殊风格的模拟框架

票数 12
EN

Stack Overflow用户

发布于 2008-09-07 00:16:49

出于期望,我通常更喜欢使用mock。当您在存根上调用返回值的方法时,它通常只是返回值。但是,当您在mock上调用一个方法时,它不仅返回值,而且还强制要求您设置该方法最初被调用的期望。换句话说,如果您设置了一个期望,然后不调用该方法,则会抛出异常。当你设置一个期望时,你实际上是在说“如果这个方法没有被调用,那就是出了问题”。反之亦然,如果你在mock上调用一个方法,并且没有设置期望,它将抛出一个异常,本质上是在问“嘿,你为什么要在你没有预料到的时候调用这个方法呢?”

有时您不希望在调用的每个方法上都有期望,因此一些模拟框架将允许类似于模拟/存根混合的“部分”模拟,因为只有您设置的期望才会被强制执行,而其他方法调用更像是一个存根,因为它只返回一个值。

不过,我能想到的一个有效的使用存根的地方是,当您将测试引入遗留代码时。有时,通过对正在测试的类进行子类化来创建存根,要比重构一切以使模仿变得容易甚至可能更容易。

还有这个..。

总是避免使用模拟,因为它们会使测试变得脆弱。如果模拟的接口发生变化,您的测试现在对实现调用的方法有了复杂的了解……你的测试失败了。所以使用你最好的judgment..<

...I说如果我的界面改变了,我的测试最好中断。因为单元测试的全部意义在于,它们可以准确地测试当前存在的代码。

票数 8
EN

Stack Overflow用户

发布于 2008-09-06 20:05:43

这取决于你正在做什么类型的测试。如果您正在进行基于行为的测试,那么您可能需要一个动态模拟,这样您就可以验证与您的依赖项之间是否发生了一些交互。但是,如果您正在进行基于状态的测试,那么您可能需要一个存根,因此您需要验证值/etc

例如,在下面的测试中,您会注意到我清除了视图,这样我就可以验证属性值是否已设置(基于状态的测试)。然后,我创建了一个服务类的动态模拟,这样我就可以确保在测试期间调用特定的方法(基于交互/行为的测试)。

代码语言:javascript
复制
<TestMethod()> _
Public Sub Should_Populate_Products_List_OnViewLoad_When_PostBack_Is_False()
    mMockery = New MockRepository()
    mView = DirectCast(mMockery.Stub(Of IProductView)(), IProductView)
    mProductService = DirectCast(mMockery.DynamicMock(Of IProductService)(), IProductService)
    mPresenter = New ProductPresenter(mView, mProductService)
    Dim ProductList As New List(Of Product)()
    ProductList.Add(New Product())
    Using mMockery.Record()
        SetupResult.For(mView.PageIsPostBack).Return(False)
        Expect.Call(mProductService.GetProducts()).Return(ProductList).Repeat.Once()
    End Using
    Using mMockery.Playback()
        mPresenter.OnViewLoad()
    End Using
    'Verify that we hit the service dependency during the method when postback is false
    Assert.AreEqual(1, mView.Products.Count)
    mMockery.VerifyAll()
End Sub
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47749

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档