使用FakeItEasy,是否可以创建一个采用泛型类型参数的虚拟对象

时间:2014-12-28 23:47:19

标签: c# .net mocking xunit.net fakeiteasy

我有以下测试:

[Fact]
public void StartProgram_CallsZoneProgramStart()
{
    var zone = A.Fake<Zone>();
    zone.StartProgram();
    A.CallTo(() => zone.ZoneProgram.Start(null, A.Dummy<ActionBlock<InterruptInfo>>())).MustHaveHappened(Repeated.Exactly.Once);
}

它正在创建一个类型为ActionBlock<InterruptInfo>的虚拟对象,它正被传递给MustHaveHappened调用。 zone.StartProgram肯定会调用zone.ZoneProgram.Start方法,但FakeItEasy看不到此调用。它返回以下错误消息:

Assertion failed for the following call:
  ZoneLighting.ZoneProgramNS.ZoneProgram.Start(<NULL>, ActionBlock\`1 Id=1)
Expected to find it exactly once but found it #0 times among the calls:
  1: ZoneLighting.ZoneProgramNS.ZoneProgram.Start(inputStartingValues: Faked ZoneLighting.ZoneProgramNS.InputStartingValues, interruptQueue: ActionBlock`1 Id=2)
  2: ZoneLighting.ZoneProgramNS.ZoneProgram.Start(inputStartingValues: <NULL>, interruptQueue: ActionBlock`1 Id=2)

从错误消息中可以看出,被比较的ActionBlocks上的ID是不同的(1和2),这就是为什么它无法看到调用的原因。我的问题是,为什么dummied ActionBlock的ID = 1?我认为它是一个虚拟对象,它不应该像ID等那样具有任何具体细节。这是因为泛型类型不能被愚弄吗?

我在这里看到了类似的内容:https://github.com/FakeItEasy/FakeItEasy/issues/402

但我无法弄清楚这是不是在谈论同一件事。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:3)

我对ActionBlock不熟悉,所以我不确定他们从Id获取Dummy值,但我想我可以了解你的测试中发生了什么。

首先,我认为你对ActionBlock<InterruptInfo>的含义感到困惑。如果是这样,不要感觉不好。它们可能有点令人困惑。来自Dummy documentation,假人是

  

Dummy是FakeItEasy在需要某种类型的对象时可以提供的对象,但该对象的实际行为并不重要。

当它需要创建一个对象来提供给类构造函数时(我们稍后会看到更多关于它的内容),或者当它需要从方法或属性返回一个不可伪造的对象时,它们主要由FakeItEasy本身使用。最终用户很少需要创建它们。

Dummy是一个真实的物体(它必须是 - 否则,我们怎么能用它做任何事情?)。它必须具有其类型具有的任何具体细节(在本例中为ActionBlock<InterruptInfo>)。对Dummying泛型类型没有限制。

查看how a Dummy is made的文档,我们可以看到,因为IDummyDefinition可能没有自定义ActionBlock<InterruptInfo>可用(你有吗?),而且它不是任务,这不是假的(因为课程是密封的),然后通过调用其中一个ActionBlock constructors制作假人,假人被用来使每个论点都满意。

我猜ActionBlocks有ID。如何分配它们,我不知道,但如果它们是一个好的ID,那么看起来我们有两个不同的zone.StartProgram:一个在Equals提供,而Dummy在测试

ActionBlocks文档表明它不会覆盖zone.ZoneProgram.Start,因此将执行引用比较,并且两个ActionBlocks(Dummy和生产代码中使用的那个)不匹配。这就是FakeItEasy无法识别电话的原因。

如果您只是试图查看是否使用第一个参数null调用A.CallTo(() => zone.ZoneProgram.Start(null, A<ActionBlock<InterruptInfo>>.Ignored)) .MustHaveHappened(Repeated.Exactly.Once); 而第二个参数调用了一些ActionBlock,我认为您可能打算使用:

Ignored

_也可以缩短为zone.ZoneProgram.Start。如果您愿意,请详细了解ignoring argument values。)

虽然我担心两件事情,但这可能会让你解决你的问题:

  1. 看起来IDummyDefinition被调用了两次,而不是“Exactly.Once”,但我相信你能够处理这个,
  2. 通常,伪装被测物体被认为是反模式。通常,一个虚拟依赖项提供给测试中的生产代码。我不是说它不会起作用,但有时它会导致混乱。在目前的问题得到解决之后,这可能是另一天的问题。
  3. 我希望这有点帮助。

    哦,你问过问题402.那个问题是在定义定制类时给用户更多的力量来控制假人的创建方式。除非您已经开设了DummyDefinition或{{1}}的课程,否则此时可能不相关。