Rhino Mocks 存根和模拟仅适用于接口?

发布于 2024-08-24 18:28:37 字数 721 浏览 2 评论 0原文

Rhino Mocks 存根和模拟仅适用于接口,而不适用于具体类,这是正确的吗?我花了相当多的时间试图让这段代码正常工作。我没想到存根的 pubSubClient 总是从类中调用 Send 方法。该方法有一些依赖性并引发异常。

[Test]
public void Test01()
{
    PubSubMessage psm = new PubSubMessage(); 
    var pubSubClient = MockRepository.GenerateStub<PubSubClient>();
    pubSubClient.Stub(x => x.Send(psm)).IgnoreArguments().Return(null);
    // actual PubSubClient Send method throws exception
    // the rest of the test is skipped...
}

但是,当我提取接口并使用 IPubSubClient 运行相同的测试时,它似乎按预期工作。

这是否意味着我必须为每个我想用 Rhino 模拟/存根的类提取接口?或者我在技术上或概念上遗漏了一些东西?

更新:好的,看来我找到了我遗漏的部分: Rhino Mocks 无法拦截对非虚拟方法的调用。所以,我想我要么使用接口,要么将具体类上的每个方法设为虚拟。如果还有其他选择,请纠正我。

Is it correct that Rhino Mocks stubs and mocks are only good for interfaces, not concrete classes? I spent quite a time trying to make this piece of code working. I did not expect the stubbed pubSubClient to always call Send method from the class. That method has some dependencies and throws exception.

[Test]
public void Test01()
{
    PubSubMessage psm = new PubSubMessage(); 
    var pubSubClient = MockRepository.GenerateStub<PubSubClient>();
    pubSubClient.Stub(x => x.Send(psm)).IgnoreArguments().Return(null);
    // actual PubSubClient Send method throws exception
    // the rest of the test is skipped...
}

However, when I have extracted the interface and run the same test with IPubSubClient, it seems to be working as expected.

Does it mean that I have to extract the interface for every class I want to mock/stub with Rhino? Or I am missing something, technically or conceptually?

UPDATE: OK, It seems I figured out what part I was missing:
Rhino Mocks cannot intercept calls to non-virtual methods. So, I guess I have either use interfaces or make every method on the concrete class virtual. Please correct me if there's another option.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你げ笑在眉眼 2024-08-31 18:28:38

布莱恩关于使用部分模拟的答案是不正确的。这不是部分模拟的目的。

Jon Erickson 的答案大部分是正确的:Rhino Mocks 和 Moq 无法拦截非虚拟调用,也无法拦截静态方法或属性。这意味着你不能伪造以下内容:

DateTime.Now; // static property, can't fake static property
someClass.SomeNonVirtualMethod(); // can't fake non-virtual method
sealedClass.Foo(); // can't fake anything on sealed classes
Utilities.SomeStaticMethod(); // can't fake static methods
someList.Any(); // can't fake extension methods like Linq's .Any()

TypeMock 可以伪造这些,正如 Jon 提到的。

应该注意的是,还有一个额外的模拟框架可以拦截所有调用:Microsoft Moles 框架。它的工作方式与 TypeMock 相同,它使用 .NET Profiler API 来拦截调用。

Moles 是免费的(目前)。这也是测试版。 Moles 仅适用于 Microsoft Pex 工具。而且它的API明显不如TypeMock精致、优雅的API。

Bryan's answer of using partial mocks is incorrect. That's not what partial mocks are for.

Jon Erickson's answer is mostly correct: Rhino Mocks and Moq can't intercept non-virtual calls, nor can they intercept static methods or properties. That means you can't fake the following:

DateTime.Now; // static property, can't fake static property
someClass.SomeNonVirtualMethod(); // can't fake non-virtual method
sealedClass.Foo(); // can't fake anything on sealed classes
Utilities.SomeStaticMethod(); // can't fake static methods
someList.Any(); // can't fake extension methods like Linq's .Any()

TypeMock can fake these, as Jon mentioned.

It should be noted there is an additional mocking framework that can intercept all calls: the Microsoft Moles framework. It works the same way TypeMock does, it uses the .NET profiler API to intercept calls.

Moles is free (for now). It's also beta. Moles only only works with Microsoft Pex tools. And its API is clearly inferior to TypeMock's refined, elegant API.

ヤ经典坏疍 2024-08-31 18:28:38

您必须使这些方法变得虚拟。 Rhino 模拟(以及大多数其他隔离框架)利用代理类来创建存根/模拟。

如果您使用 TypeMock Isolator,您可以模拟任何内容,因为此隔离框架利用 .NET Profiler API 来创建其“存根/模拟”

You have to make the methods virtual. Rhino mocks (and most other isolation frameworks) utilizes proxy classes in order to create the stubs/mocks.

If you use TypeMock Isolator you can mock anything because this isolation framework utilizes the .NET Profiler API in order to create its' stubs/mocks

流心雨 2024-08-31 18:28:38

这基本上是正确的,并且通常是良好的做法。然而,它只对特定类型的编码真正有用

不要将物体视为某种“更高力量”可以操纵的东西。相反,将他们视为可以互相发送消息的自主“人”。接口代表单个对象发送的消息。

然后,您使用模拟来验证是否发送了正确的消息,而不是提供依赖项的虚假实现。

理想情况下,您不会创建与现有类完全匹配的接口 - 相反,使用该接口的类以接口的形式声明其需求。

That's essentially correct, and is generally good practice. However, it's only really useful for a specific type of coding.

Don't think of objects as things that some 'higher power' can manipulate. Instead, think of them as autonomous 'people' that can send messages to each other. An interface represents the messages sent by a single object.

You then use mocks to verify that the correct messages were sent, not to provide fake implementations of dependencies.

Ideally, you don't create an interface that exactly matches an existing class - instead, the class consuming the interface declares its needs in the form of an interface.

故人如初 2024-08-31 18:28:38

部分模拟允许您模拟具体类的功能。请参阅:http://www.ayende.com/wiki/Rhino+模拟+部分+Mocks.ashx

Partial mocks allow you to mock out functionality of a concrete class. See: http://www.ayende.com/wiki/Rhino+Mocks+Partial+Mocks.ashx

你是年少的欢喜 2024-08-31 18:28:38

我认为除了使任何想要模拟的方法成为虚拟之外,没有其他方法可以做到这一点 - 我相信创建具体类的模拟的方式是通过动态子类化被模拟的具体类,然后用以下命令覆盖给定的方法您在测试中指定的行为,因此这需要虚拟方法才能正常工作。

I don't think there's another way of doing this other than making any methods you want to mock virtual - I believe the way mocks of concrete classes are created is by dynamically sub-classing the concrete class being mocked and then overriding the given methods with the behaviour you specify in the test, so this requires a virtual method to work correctly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文