C# 中的起订量设置混乱

发布于 2024-08-12 16:11:33 字数 863 浏览 2 评论 0原文

所以我有以下课程:

public class MyClass {
  internal void A() {
    foreach(Thing thing in ThingArray)
      B(thing);
  }

  virtual internal void B(Thing thing)
  {
    //  do some stuff
  }
}

然后我有以下测试:

...
var testObject = new Mock<MyClass>(parameters);
testObject.Setup(t => t.B(It.IsAny<Thing>()));

test.Object.A();

test.Verify(t => t.B(It.IsAny<Thing>()), Times.Exactly(2));

验证失败。我已经检查过,代码正在调用 real B() 方法,而不是模拟的 B() 方法。

我有很多代码在 Moq 完美运行的地方运行,而且我已经编码了足够长的时间,意识到我一定在这里做错了什么,但我一生都看不到它。我一直在假设自从我调用 test.Object.A() 以来,对 B() 的调用不会通过模拟,但这确实不会产生任何影响对我来说很有意义,因为来自任何其他对象的调用都会起到相同的作用......

那么到底为什么模拟的设置没有被执行呢?

编辑:是的,我有测试项目可见的内部结构。我本来打算将其放入原始帖子中,因为我知道有人会提到它。

至于真正的代码,不幸的是它是非常专有的,所以我不能发布它。明天我会看看是否可以调整代码以使其真正编译。

So I have the following class:

public class MyClass {
  internal void A() {
    foreach(Thing thing in ThingArray)
      B(thing);
  }

  virtual internal void B(Thing thing)
  {
    //  do some stuff
  }
}

And then I have the following test:

...
var testObject = new Mock<MyClass>(parameters);
testObject.Setup(t => t.B(It.IsAny<Thing>()));

test.Object.A();

test.Verify(t => t.B(It.IsAny<Thing>()), Times.Exactly(2));

And the verify is failing. I've checked, and the code is calling the real B() method as opposed to a mocked B() method.

I've got a lot of code running where Moq works perfectly, and I've been coding long enough to realize that I must be doing something wrong here, but for the life of me I can't see it. I've been proceeding under the assumption that since I'm calling test.Object.A(), the calls to B() are not going through the Mock, but that really doesn't make any sense to me since a call from any other object would work the same...

So why on earth isn't the mocked setup being executed?

Edit: Yes, I have the internals visible to the test project. I meant to put that into the original post, since I knew someone would mention it.

As to the real code, it is unfortunately VERY proprietary, so I can't post it. I'll see if I can adjust the code tomorrow to make it actually compile.

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

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

发布评论

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

评论(4

孤独患者 2024-08-19 16:11:33

您的 Mock 对象必须满足以下条件才能成功模拟方法:

  • 它必须是一个接口
  • 或者您要模拟的方法必须是虚拟方法并且是公共的。

现在您还可以模拟虚拟内部方法,但为了允许您必须授予 Moq 访问内部的权限。您可以这样做:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

这使得 Moq 的代码生成器可以访问内部。

因此,为了模拟您的 MyClass.A 调用,您必须执行以下操作:

  1. 将方法 A 设为虚拟。
  2. 并公开您的方法或允许访问

    [程序集:InternalsVisibleTo("DynamicProxyGenAssembly2")]
    

或者如前所述,创建一个代表 MyClass 的 API 的接口。

The object your Mock has to meet this criterias in order to make a successfully mock a method:

  • It has to be an interface
  • Or the method you want to mock has to be a virtual method and public.

Now you can also mock virtual-internal method, but in order to allow that you have to give Moq access to your internals. This you can do with:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

This make the internal accessible to the code-generator of Moq.

So in order to mock your MyClass.A call you have to do this:

  1. Make you method A virtual.
  2. And make your method public or allow access with

    [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
    

Or as said, make an interface which represents the API of MyClass.

玻璃人 2024-08-19 16:11:33

我不确定 Gamlor 的答案是否有效。看来,如果您想对某个方法执行设置,并验证 Class1.MethodA 是否调用 Class1.MethodB,则 MethodB(您要对其进行设置的方法)必须是公共的(无论 InternalsVisibleTo 是多少)。我在类似的情况下编写了一个简单的测试,发现一旦我公开了 MethodB,Moq 就开始工作了。我敢打赌,如果你公开你的方法 B,它就会起作用。

我认为这是 Castle 或 Moq 错误,但我不确定。希望有人能插话。

我知道公开 MethodB 不是一个好的选择。但这就是我所知道的情况......

I'm not sure if Gamlor's answer works. It seems that if you want to perform a setup on a method where you want to verify that Class1.MethodA calls Class1.MethodB, MethodB (which is the one you would do the setup on) has to be public (regardless of InternalsVisibleTo). I wrote a simple test under a similar situation and found that once I made my MethodB public, Moq started working. I would bet if you made your method B public, it would work.

I assume this is a Castle or Moq bug but I don't know for sure. Hopefully somebody will chime in.

I know making MethodB public is not a good choice. But that is what I know about the situation...

蓝天 2024-08-19 16:11:33

Moq 不会包装现有代码,而是创建一个空的模拟。

这意味着调用 testObject.Object.A() 不会执行您的原始代码,因此永远不会调用 B。

如果您假装模拟一个接口,那么这是有道理的,因为接口没有代码,所以模拟也没有代码。

Moq doesn't wrap the existing code, but instead creates an empty mock.

That means that calling testObject.Object.A() doesn't execute your original code, so B is never called.

If you pretend your mocking an interface then this makes sense because interfaces don't have code, so neither would the mock.

酒儿 2024-08-19 16:11:33

尝试像这样创建模拟(我没有尝试,所以我不知道它是否有效):

var testObject= new Mock<MyClass> { CallBase = true };

Try creating the mock like this (I didn't try it so I don't know if it works):

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