其他分享
首页 > 其他分享> > CodeGo.net>使用FakeItEasy,可以创建一个使用通用类型参数的类型的虚拟对象

CodeGo.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),这就是为什么它无法看到已进行调用的原因.我的问题是,为什么虚拟的ActionBlock的ID = 1?我以为是虚拟对象,它不应该包含ID等其他详细信息.这是因为无法对通用类型进行虚拟化吗?

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

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

解决方法:

我对ActionBlocks并不熟悉,因此不确定它们从何处获取其Id值,但我认为我可以对您测试中的情况有所了解.

首先,我认为您对Dummy是什么感到困惑.如果是这样,不要难过.他们可能会有些混乱.从Dummy documentation开始,假人是

Dummy is an object that FakeItEasy can provide when an object of a certain type is required, but the actual behavior of the object is not important.

当需要创建一个对象以馈给类构造函数的对象时,它们通常由FakeItEasy本身使用(稍后将对此进行详细介绍),或者需要从方法或属性返回不可伪造的对象时,FakeItEasy本身将使用它们.最终用户很少需要创建它们.

虚拟对象是一个实际的对象(必须是-否则,我们如何对其进行处理?).它必须具有其类型具有的任何具体细节(在这种情况下,为ActionBlock< InterruptInfo>). Dummying泛型类型没有任何限制.

查看how a Dummy is made的文档,我们可以看到,由于ActionBlock< InterruptInfo>可能没有可用的自定义IDummyDefinition(您有一个吗?),它不是Task,也不是可伪造的(因为该类是密封的),因此通过调用ActionBlock constructors中的一个创建了Dummy,其中Dummies是使每个论点都满足.

我猜想ActionBlocks有ID.我不知道如何分配它们,但是如果它们是一个很好的ID,则看起来我们有两个不同的ActionBlock< InterruptInfo&gt ;:在zone.StartProgram中提供了一个,并且在测试中制造了Dummy. ActionBlocks文档建议不要覆盖Equals,因此将执行参考比较,并且两个ActionBlock(虚拟对象和生产代码中使用的一个)不匹配.这就是FakeItEasy无法识别呼叫的原因. 如果您只是想查看是否使用第一个参数为null且第二个参数为某些ActionBlock调用了zone.ZoneProgram.Start,我认为您可能打算使用:

A.CallTo(() => zone.ZoneProgram.Start(null, A<ActionBlock<InterruptInfo>>.Ignored))
            .MustHaveHappened(Repeated.Exactly.Once);

(也可以将其缩写为_.如果您愿意,请阅读有关ignoring argument values的更多信息.)

尽管我对两件事感到担忧,但这可能会让您摆脱眼前的问题:

>看起来好像是zone.ZoneProgram.Start被调用了两次,而不是“ Exactly.Once”,但是我确信您将能够处理该问题,并且
>通常,伪造被测对象被视为一种反模式.通常情况下,一个伪造的依赖关系会提供给受测试的生产代码.我并不是说这行不通,但有时会导致混乱.在解决当前问题之后,仍然有一天可能会出现问题.

我希望能有所帮助.

哦,您问了问题402.该问题是有关在定义将控制如何创建虚拟对象的自定义类时为用户提供更多功能的.除非您制作了扩展IDummyDefinition或DummyDefinition的类,否则在这一点上可能不相关.

标签:xunit-net,fakeiteasy,mocking,c,net
来源: https://codeday.me/bug/20191120/2047562.html