你怎么模仿密封课程?

Bre*_*tra 61 language-agnostic tdd unit-testing mocking

模拟密封课程可能会非常痛苦.我目前赞成使用适配器模式来处理这个问题,但是有些事情让我觉得很奇怪.

那么,你嘲笑密封课程的最佳方式是什么?

Java答案非常受欢迎.实际上,我预计Java社区已经处理了这个问题,并且提供了很多东西.

但这里有一些.NET意见:

Haa*_*ked 19

对于.NET,您可以使用TypeMock之类的东西,它使用分析API并允许您挂钩几乎任何东西的调用.

  • 有些人可能不喜欢每月支付80美元用于测试框架. (9认同)
  • +1.使用正确的工具.不要让工具决定你应该怎么做.API适用于人,而不适用于工具 - 如此设计.在有意义的地方使用DI和接口以及完全去耦,这不仅仅是因为您需要它来用于测试工具. (7认同)
  • Pavel - 问题在于.NET中的"正确"方式通常会引导您走"使用TypeMock进行测试"的路径.遵循只有一种可用测试工具的路径似乎也不是很好. (2认同)

Mat*_*ias 13

我相信微软研究院的Moles允许你这样做.从Moles页面:

Moles可用于绕过任何.NET方法,包括密封类型中的非虚拟/静态方法.

更新:在即将发布的VS 11版本中有一个名为"Fakes"的新框架,旨在取代Moles:

Visual Studio 11中Fakes Framework是下一代Moles&Stubs,最终将取代它.假货与Moles不同,因此从Moles转向Fakes需要对代码进行一些修改.此迁移的指南将在以后提供.

要求:Visual Studio 11 Ultimate,.NET 4.5


aby*_*byx 9

我的一般经验法则是我需要模拟的对象也应该有一个共同的接口.我认为这是正确的设计,使测试更容易(通常是你做TDD时得到的).有关这方面的更多信息,请参阅Google测试博客最新帖子(参见第9点).

此外,在过去的4年里,我一直在Java工作,我可以说,我可以依靠我创建最终(密封)课程的次数.这里的另一个规则是我应该总是有充分的理由密封一个类,而不是默认密封它.

  • 我认为你应该有一个很好的理由*不*密封课程.让一个类保持打开意味着你需要考虑继承者如何使用它,这会打开关于类中所有代码(虚拟,受保护属性或私有成员变量等)的决策的大门.这很难*正确设计继承类.你不应该只是为了扩展而扩展课程; 推导应该意味着特定于被建模的问题.否则,请改用合成. (23认同)
  • @BryanWatts我强烈反对这一点.密封一个类只会让编码人员无法继承该类.他们可能会发现以一种你没有预料到的方式扩展它.你不需要担心它们会以某种方式搞砸了; 它(可能)不是你的责任.我实际上取消了`sealed`关键字. (7认同)
  • @abyx:不幸的是,一个班级是否被密封并不总是开发人员的选择.以ASP.NET中的System.Web.HttpServerUtility为例...... (6认同)
  • @Jez:如果我在写课时没有考虑过延期,那么有什么理由相信呢? (3认同)
  • 强烈同意@Jez。很高兴看到官方指南有相同的意见:“没有充分的理由不要密封类。因为无法想到可扩展性场景而密封类不是一个很好的理由。” (https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/sealing) 为了保护方法不被子类滥用,只需将它们设为私有即可。还不够吗? (3认同)
  • 布莱恩 - 那么你怎么会嘲笑一个密封的课呢?从理论的角度来看,我同意你的看法,但是如果你写一些依赖于密封课程的东西,那么你的考试也取决于密封课程. (2认同)

小智 7

我最近遇到了这个问题,在阅读/搜索网络后,除了使用上面提到的另一个工具之外,似乎没有简单的方法。或者像我一样粗鲁地处理事情:

  • 创建密封类的实例而不调用构造函数。

  • System.Runtime.Serialization.FormatterServices.GetUninitializedObject(instanceType);

  • 通过反射为属性/字段赋值

  • YourObject.GetType().GetProperty("PropertyName").SetValue(dto, newValue, null);

  • YourObject.GetType().GetField("FieldName").SetValue(dto, newValue);


Bra*_*son 6

TypeMock 的问题在于它可以为糟糕的设计找借口。现在,我知道它隐藏的通常是其他人的糟糕设计,但是允许它进入您的开发过程很容易导致允许您自己的糟糕设计。

我认为如果你打算使用一个模拟框架,你应该使用传统的框架(比如 Moq)并围绕不可模拟的东西创建一个隔离层,然后模拟隔离层。

  • 不要仅仅因为您的测试工具的缺陷而需要它们就在眼前的所有东西上拍打接口并不是一个糟糕的设计。事实上,恰恰相反 - _sane_ 设计是关于设计的,而不是关于符合你的工具。我发誓,有时我认为 TDD 经常被教条地实践,真的应该被称为“工具驱动的设计”。另见 http://weblogs.asp.net/rosherove/archive/2008/01/17/is-typemock-too-powerful-will-it-kill-design-for-testability.aspx (12认同)
  • 我同意布拉德的看法。创建模拟对象意味着您正在测试该类型的公共行为。也就是说,您具体说的是,“我需要此对象的公共 API 以某种方式运行。” 此行为与实现的 API 无关。这意味着你有一个已经定义的(虽然是隐式的)抽象,它需要以某种方式表现。在静态类型系统中,这必须通过创建抽象类型来明确。 (2认同)