Mocking sealed classes可能会非常痛苦。我目前赞成使用Adapter pattern来处理这个问题,但有些事情让我觉得很奇怪。
那么,你嘲笑密封班的最佳方式是什么?
Java答案非常受欢迎。事实上,我预计Java社区已经处理这个问题的时间越来越长,并且提供了大量的服务。
但这里有一些.NET意见:
答案 0 :(得分:18)
对于.NET,你可以使用类似TypeMock的东西,它使用分析API并允许你挂钩几乎任何东西的调用。
答案 1 :(得分:13)
我相信来自Microsoft Research的{{3}}允许您这样做。从Moles页面:
Moles可用于绕道任何.NET 方法,包括非虚拟/静态 密封类型的方法。
UPDATE:在即将推出的VS 11版本中有一个名为“Fakes”的新框架,旨在取代Moles:
Moles是下一代Moles&存根,并最终将取代它。假货与Moles不同,因此从Moles转向Fakes需要对代码进行一些修改。此迁移指南将在以后提供。
要求:Visual Studio 11 Ultimate,.NET 4.5
答案 2 :(得分:7)
我的一般经验法则是我需要模拟的对象也应该有一个共同的接口。我认为这是正确的设计,使测试更容易(通常是你做TDD时得到的)。有关这方面的更多信息,请参阅Google测试博客latest post(参见第9点)。
另外,在过去的4年里,我一直在Java工作,我可以说我可以一手掌握我创建最终(密封)课程的次数。这里的另一个规则是我应该总是有充分的理由来密封一个类,而不是默认密封它。
答案 3 :(得分:4)
TypeMock的问题在于它可以为糟糕的设计辩解。现在,我知道它隐藏了其他人糟糕的设计,但允许它进入你的开发过程可能很容易导致你自己的糟糕设计。
我认为如果你要使用一个模拟框架,你应该使用一个传统的框架(比如Moq)并围绕不可迁移的东西创建一个隔离层,而不是模拟隔离层。
答案 4 :(得分:4)
我几乎总是避免在我的代码深处依赖外部类。相反,我宁愿使用适配器/桥接器与他们交谈。这样,我正在处理我的语义,翻译的痛苦在一个类中被隔离。
从长远来看,它还可以更轻松地切换我的依赖项。
答案 5 :(得分:2)
我最近遇到了这个问题,在阅读/搜索网页后,似乎没有简单的方法,除了使用上面提到的其他工具。 或者像我一样粗暴地处理事情:
System.Runtime.Serialization.FormatterServices.GetUninitializedObject(instanceType);
通过反射为您的属性/字段指定值
答案 6 :(得分:1)
我通常采用创建接口和适配器/代理类的路线来促进密封类型的模拟。但是,我还尝试跳过界面的创建,并使用虚拟方法使代理类型不被密封。当代理实际上是封装和用户密封类的一部分的自然基类时,这很有效。
在处理需要这种改编的代码时,我厌倦了执行相同的操作来创建接口和代理类型,所以我实现了一个库来自动完成任务。
代码比您引用的文章中给出的示例稍微复杂一些,因为它生成一个程序集(而不是源代码),允许在任何类型上执行代码生成,并且不需要那么多配置
有关详细信息,请参阅this page。
答案 7 :(得分:1)
模拟密封类是完全合理的,因为许多框架类都是密封的。
在我的情况下,我正在尝试模拟.Net的MessageQueue类,以便我可以TDD我优雅的异常处理逻辑。
如果有人对如何克服Moq关于“无法覆盖的成员的无效设置”的错误有任何想法,请告诉我。
代码:
[TestMethod]
public void Test()
{
Queue<Message> messages = new Queue<Message>();
Action<Message> sendDelegate = msg => messages.Enqueue(msg);
Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate =
(v1, v2) =>
{
throw new Exception("Test Exception to simulate a failed queue read.");
};
MessageQueue mockQueue = QueueMonitorHelper.MockQueue(sendDelegate, receiveDelegate).Object;
}
public static Mock<MessageQueue> MockQueue
(Action<Message> sendDelegate, Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate)
{
Mock<MessageQueue> mockQueue = new Mock<MessageQueue>(MockBehavior.Strict);
Expression<Action<MessageQueue>> sendMock = (msmq) => msmq.Send(It.IsAny<Message>()); //message => messages.Enqueue(message);
mockQueue.Setup(sendMock).Callback<Message>(sendDelegate);
Expression<Func<MessageQueue, Message>> receiveMock = (msmq) => msmq.Receive(It.IsAny<TimeSpan>(), It.IsAny<MessageQueueTransaction>());
mockQueue.Setup(receiveMock).Returns<TimeSpan, MessageQueueTransaction>(receiveDelegate);
return mockQueue;
}
答案 8 :(得分:1)
虽然目前仅在测试版中提供,但我认为值得记住新shim的Fakes framework功能(Visual Studio 11 Beta版本的一部分)。
Shim类型提供了一种将任何.NET方法绕道到用户定义的委托的机制。 Shim类型是由Fakes生成器代码生成的,它们使用委托(我们称之为shim类型)来指定新的方法实现。在引擎盖下,填充类型使用在运行时在方法MSIL主体中注入的回调。
就我个人而言,我正在使用它来模拟密封框架类(如DrawingContext。
)上的方法答案 9 :(得分:0)
有没有办法从接口实现密封类...而是模拟界面?
我身上有些东西觉得密封课程首先是错误的,但那只是我:)
答案 10 :(得分:0)
您可以使用免费且获得 MIT 许可的 Mocksanity。