我们如何模拟密封课程?
模拟密封课程可能会很痛苦。我目前更喜欢使用Adapter模式来处理此问题,但是有些事情总是让人觉得很奇怪。
那么,模拟密封类的最佳方法是什么?
非常欢迎Java的答案。实际上,我希望Java社区已经对此进行了较长的处理,并且可以提供很多帮助。
但是,这里有一些.NET意见:
- 为什么鸭子为C#开发人员键入内容很重要
- 创建密封包装和其他类型的包装以进行模拟
- WCF(和Moq)的单元测试
解决方案
回答
有没有一种方法可以从接口实现密封类并模拟接口呢?
我内心有些感觉,一开始就有密封的类是错误的,但这就是我自己:)
回答
我的一般经验法则是,我需要模拟的对象也应该有一个公共接口。我认为这是正确的设计方式,并且使测试变得容易得多(通常,如果执行TDD,通常会得到此结果)。有关此问题的更多信息,请参阅Google Testing Blog最新文章(请参阅第9点)。
另外,在过去的四年中,我主要从事Java工作,我可以说一方面可以指望我创建最终(密封)类的次数。这里的另一个规则是,我应该总是有一个很好的理由来密封一个类,而不是默认情况下密封它。
回答
对于.NET,我们可以使用TypeMock之类的东西,它使用概要分析API,并允许我们挂接对几乎所有内容的调用。
回答
TypeMock的问题在于它会为不良设计辩解。现在,我知道它通常隐藏着其他人的不良设计,但是将其允许进入开发过程可以很容易地导致允许我们自己的不良设计。
我认为,如果要使用模拟框架,则应使用传统框架(例如Moq),并在不可模拟的事物周围创建隔离层,然后模拟隔离层。
回答
我通常采用创建接口和适配器/代理类的途径来简化密封类型的模拟。但是,我还尝试过跳过接口的创建,并使代理类型不与虚拟方法密封。当代理实际上是封装并使用密封类的用户部分的自然基类时,此方法很好用。
在处理需要这种修改的代码时,我厌倦了执行相同的操作来创建接口和代理类型,因此实现了一个库来自动执行任务。
该代码比我们所引用的文章中的示例要复杂得多,因为它会生成一个程序集(而不是源代码),允许以任何类型执行代码生成,并且不需要太多配置。
有关更多信息,请参阅此页面。
回答
我几乎总是避免在代码中深入依赖外部类。相反,我宁愿使用适配器/桥接器与他们交谈。这样,我就在处理我的语义,翻译的痛苦被隔离在一个类中。
从长远来看,这也使切换我的依赖关系变得更加容易。
回答
模拟密封类是完全合理的,因为许多框架类都是密封的。
就我而言,我试图模拟.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; }
回答
我相信Microsoft Research的Moles可以做到这一点。在"痣"页面上:
Moles may be used to detour any .NET method, including non-virtual/static methods in sealed types.
更新:即将发布的VS 11版本中有一个名为" Fakes"的新框架,旨在取代Moles:
The Fakes Framework in Visual Studio 11 is the next generation of Moles & Stubs, and will eventually replace it. Fakes is different from Moles, however, so moving from Moles to Fakes will require some modifications to your code. A guide for this migration will be available at a later date. Requirements: Visual Studio 11 Ultimate, .NET 4.5