使用 RhinoMock 或 Moq 测试方法的内部结构

发布于 2024-08-15 08:14:47 字数 213 浏览 5 评论 0原文

我对这个嘲笑的事情很陌生,我有几个问题。

如果我错了请纠正我: 模拟不会初始化真正的方法,即模拟不会实际调用类的构造函数。相反,它会执行类似查看类的签名并创建具有该签名但不具有任何方法功能的对象的操作。如果您只需要该类型的对象但不想测试它的内部结构(例如,如果您实际测试的对象对其有依赖关系),这非常有用。

我正在尝试测试方法的内部结构,这是否意味着我必须创建该方法所属类的实例?

Quite new to this mocking thing, I have a couple of questions.

Correct me if I'm wrong:
Mocking does not initialize the real method i.e. Mocking will not actually call the constructor of your class. Instead it does something like look at the signature of the class and create an object with that signature but with none of the methods functionality. This is useful if you just need an object of that type but don't want to test it's internals, e.g. if the object you're actually testing has a dependency on it.

I'm trying to test the internals of a method, does this mean I must create an instance of the class that the method belongs to?

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

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

发布评论

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

评论(1

酷遇一生 2024-08-22 08:14:47

摘要:动态模拟不会帮助您测试类型的内部结构,但您不应该首先尝试这样做。


你的描述基本上是正确的,但实际情况比这要复杂一些。本质上,动态模拟不会做任何你无法手动完成的事情

假设您正在针对这样的接口进行编程:

public interface IMyInterface
{
    string Foo(string s);
}

您可以手动创建 IMyInterface 的特定于测试的实现,该实现会忽略输入参数并始终返回相同的输出:

public class MyClass : IMyInterface
{
    public string Foo(string s)
    {
        return "Bar";
    }
}

但是,如果您想测试消费者响应不同的返回值,因此您可以让一个框架为您动态创建它们,而不是手动编写测试替身

想象一下,动态模拟确实编写了与上面的 MyClass 实现类似的代码(它们实际上并不编写代码,而是动态发出类型,但这是一个足够准确的类比)。

以下是如何使用 Moq 定义与 MyClass 相同的行为:

var mock = new Mock<IMyInterface>();
mock.Setup(x => x.Foo(It.IsAny<string>())).Returns("Bar");

在这两种情况下,创建对象时都会调用所创建类的构造函数。由于接口没有构造函数,因此这通常是默认构造函数(分别是 MyClass 和动态发出的类的)。

您可以对像这样的具体类型执行相同的操作:

public class MyBase
{
    public virtual string Ploeh()
    {
        return "Fnaah";
    }
}

您可以手动从 MyBase 派生并重写 Ploeh 方法,因为它是虚拟的:

public class TestSpecificChild : MyBase
{
    public override string Ploeh()
    {
        return "Ndøh";
    }
}

动态模拟库可以执行相同的操作,对于抽象方法也是如此。在这种情况下,将调用基类的构造函数,因为这就是 .NET 的工作原理。

但是,您无法编写覆盖非虚拟或内部成员的代码,动态模拟也不能。他们只能做你手工能做的事情。

不过,有一条建议:仅通过公共 API 对内部成员进行单元测试

警告:上面的描述对于大多数动态模拟都是正确的,但 TypeMock 除外,它是不同的并且......可怕。

Summary: Dynamic mocks will not help you testing the internals of your types, but you shouldn't be attempting to do that in the first place.


You are basically correct in your description, but it's a bit more complicated than that. Essentially, dynamic mocks don't do anything you couldn't do by hand.

Let's say you are programming against an interface such as this one:

public interface IMyInterface
{
    string Foo(string s);
}

You could manually create a test-specific implementation of IMyInterface that ignores the input parameter and always returns the same output:

public class MyClass : IMyInterface
{
    public string Foo(string s)
    {
        return "Bar";
    }
}

However, that becomes repetitive really fast if you want to test how the consumer responds to different return values, so instead of coding up your Test Doubles by hand, you can have a framework dynamically create them for you.

Imagine that dynamic mock really write code similar to the MyClass implementation above (they don't actually write the code, they dynamically emit the types, but it's an accurate enough analogy).

Here's how you could define the same behavior as MyClass with Moq:

var mock = new Mock<IMyInterface>();
mock.Setup(x => x.Foo(It.IsAny<string>())).Returns("Bar");

In both cases, the construcor of the created class will be called when the object is created. As an interface has no constructor, this will normally be the default constructor (of MyClass and the dynamically emitted class, respectively).

You can do the same with concrete types such as this one:

public class MyBase
{
    public virtual string Ploeh()
    {
        return "Fnaah";
    }
}

By hand, you would be able to derive from MyBase and override the Ploeh method because it's virtual:

public class TestSpecificChild : MyBase
{
    public override string Ploeh()
    {
        return "Ndøh";
    }
}

A dynamic mock library can do the same, and the same is true for abstract methods. In this case, the base class' constructor will be invoked, because that's how .NET works.

However, you can't write code that overrides a non-virtual or internal member, and neither can dynamic mocks. They can only do what you can do by hand.

A piece of advice, though: Only unit test internal members through your public API.

Caveat: The above description is true for most dynamic mocks with the exception of TypeMock, which is different and... scary.

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