Unit testing 模仿比存根好吗?
不久前,我读了Martin Fowler的文章,我必须承认我有点害怕增加复杂性的外部依赖,所以我想问: 单元测试时使用的最佳方法是什么Unit testing 模仿比存根好吗?,unit-testing,mocking,Unit Testing,Mocking,不久前,我读了Martin Fowler的文章,我必须承认我有点害怕增加复杂性的外部依赖,所以我想问: 单元测试时使用的最佳方法是什么 始终使用模拟框架来自动模拟被测试方法的依赖关系更好吗,还是更喜欢使用更简单的机制,例如测试存根?阅读Luke Kanies在中对这个问题的讨论。他引用了一篇文章,其中甚至建议使用[相当于ruby/mocha的]stub_,一切都可以让测试更加健壮。引用Fields的最后一句话:“Mocha让定义一个mock和定义一个存根一样容易,但这并不意味着你应该总是喜欢mo
始终使用模拟框架来自动模拟被测试方法的依赖关系更好吗,还是更喜欢使用更简单的机制,例如测试存根?阅读Luke Kanies在中对这个问题的讨论。他引用了一篇文章,其中甚至建议使用[相当于ruby/mocha的]stub_,一切都可以让测试更加健壮。引用Fields的最后一句话:“Mocha让定义一个mock和定义一个存根一样容易,但这并不意味着你应该总是喜欢mock。事实上,我通常更喜欢存根,并在必要时使用mock。”正如格言所说的那样“用可能工作的最简单的东西。”
所以,用你最好的判断。。我更喜欢mock,因为它可以帮助我用n>>3个方法更新一个假类 更新结语/审议:
(感谢Toran Billups的模拟测试示例。见下文)
嗨,道格,我想我们已经进入了另一场圣战——经典的TDDers vs Mockist TDDers。我想我属于前者
- 如果我在test#101 test#u ExportProductList上,我发现需要向ipProductService.GetProducts()添加一个新参数。我这样做,让这个测试变成绿色。我使用重构工具来更新所有其他引用。现在我发现所有调用这个成员的模拟测试都失败了。然后我必须回去更新所有这些测试——这是浪费时间。当返回为false失败时,为什么应该加载PopulateProductsListViewLoad?是因为密码坏了吗?相反,测试失败了。我赞成一个测试失败=一个需要修复的地方。嘲笑freq与此相反。存根会更好吗?如果我有一个假的类。GetProducts()。。确保有一个地方可以改变,而不是在多个Expect电话中进行枪战手术。归根结底,这是一个风格问题。。如果您有一个通用的实用程序方法MockHelper.SetupExpectForGetProducts()-那就足够了。。但你会发现这很少见李>
- 如果在测试名称上放置白色条带,则测试很难读取。模拟框架的大量管道代码隐藏了正在执行的实际测试
- 需要您学习模拟框架的这种特殊风格
_
当“回发”为“假”()时,公共子项应“填充”产品“列表”视图“加载”
mMockery=newmockrepository()
mView=DirectCast(mMockery.Stub(属于IPProductView)(),IPProductView)
MPProductService=DirectCast(mMockery.DynamicMock(属于IPProductService)(),IPProductService)
MPPresenter=新产品演示者(mView、MPProductService)
Dim ProductList作为新列表(产品)()
ProductList.Add(新产品())
使用mMockery.Record()
SetupResult.For(mView.PageIsPostBack).返回(False)
Expect.Call(mpProductService.GetProducts()).Return(ProductList).Repeat.Once()
终端使用
使用mMockery.Playback()
mPresenter.OnViewLoad()文件
终端使用
'当回发为false时,验证我们在方法期间是否命中了服务依赖项
Assert.AreEqual(1,mView.Products.Count)
mMockery.VerifyAll()
端接头
最好使用组合,您必须使用自己的判断。以下是我使用的指导原则:
- 如果调用外部代码是您的代码预期(外向)行为的一部分,那么应该对此进行测试。使用一个模拟
- 如果调用实际上是一个外部世界不关心的实现细节,那么最好使用存根。然而:
- 如果您担心测试代码的后续实现可能会意外地绕过存根,并且希望注意到这种情况,请使用mock。您正在将测试与代码耦合,但这是为了注意到存根不再足够,您的测试需要重新工作
同样,这是一种代码气味,也是最后的手段。如果您发现需要经常这样做,请尝试重新思考编写测试的方式。出于预期,我通常更喜欢使用模拟。当您在存根上调用返回值的方法时,它通常只返回一个值。
<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