不久前,我读到了Martin Fowler的Mocks Aren't Stubs文章,我必须承认,关于增加的复杂性,我有点害怕外部依赖,所以我想问一下:
在进行单元测试时最好的方法是什么?
总是使用模拟框架来自动模拟被测试方法的依赖关系更好,还是更喜欢使用更简单的机制,例如测试存根?
发布于 2008-09-06 20:00:24
正如这句口头语所说:“做最简单的事情,只要可能行得通。”
避免总是使用mock,因为它们会使测试变得脆弱。如果被模拟的接口或您的实现发生变化,您的测试现在对由实现调用的方法有了复杂的了解。你的测试失败了。这是不好的,因为你会花费额外的时间让你的测试运行,而不仅仅是让你的SUT运行。测试不应该与实现不适当地密切相关。
所以用你最好的判断力..我更喜欢模拟,因为它可以帮助我省去编写代码--用n>>3方法更新一个假的类。
更新前言/讨论:
(多亏了Toran Billups,例如一个mockist测试。见下文)
嗨,道格,我想我们已经进入了另一场圣战-经典TDDers vs模拟人TDDers。我想我属于前者。
。
发布于 2008-09-07 00:16:49
出于期望,我通常更喜欢使用mock。当您在存根上调用返回值的方法时,它通常只是返回值。但是,当您在mock上调用一个方法时,它不仅返回值,而且还强制要求您设置该方法最初被调用的期望。换句话说,如果您设置了一个期望,然后不调用该方法,则会抛出异常。当你设置一个期望时,你实际上是在说“如果这个方法没有被调用,那就是出了问题”。反之亦然,如果你在mock上调用一个方法,并且没有设置期望,它将抛出一个异常,本质上是在问“嘿,你为什么要在你没有预料到的时候调用这个方法呢?”
有时您不希望在调用的每个方法上都有期望,因此一些模拟框架将允许类似于模拟/存根混合的“部分”模拟,因为只有您设置的期望才会被强制执行,而其他方法调用更像是一个存根,因为它只返回一个值。
不过,我能想到的一个有效的使用存根的地方是,当您将测试引入遗留代码时。有时,通过对正在测试的类进行子类化来创建存根,要比重构一切以使模仿变得容易甚至可能更容易。
还有这个..。
总是避免使用模拟,因为它们会使测试变得脆弱。如果模拟的接口发生变化,您的测试现在对实现调用的方法有了复杂的了解……你的测试失败了。所以使用你最好的judgment..<
...I说如果我的界面改变了,我的测试最好中断。因为单元测试的全部意义在于,它们可以准确地测试当前存在的代码。
发布于 2008-09-06 20:05:43
这取决于你正在做什么类型的测试。如果您正在进行基于行为的测试,那么您可能需要一个动态模拟,这样您就可以验证与您的依赖项之间是否发生了一些交互。但是,如果您正在进行基于状态的测试,那么您可能需要一个存根,因此您需要验证值/etc
例如,在下面的测试中,您会注意到我清除了视图,这样我就可以验证属性值是否已设置(基于状态的测试)。然后,我创建了一个服务类的动态模拟,这样我就可以确保在测试期间调用特定的方法(基于交互/行为的测试)。
<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 Subhttps://stackoverflow.com/questions/47749
复制相似问题