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

C# 使用FakeiTesy,是否可以创建一个采用泛型类型参数的类型的虚拟对象,c#,.net,mocking,xunit.net,fakeiteasy,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(Re

我有以下测试:

[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);
}
[事实]
public void StartProgram_CallsZoneProgramStart()
{
var zone=A.Fake();
zone.StartProgram();
A.CallTo(()=>zone.ZoneProgram.Start(空,A.Dummy


但是我无法确定这是否是在谈论同样的事情。如果您能提供任何帮助,我将不胜感激。

我不熟悉
ActionBlock
s,因此我不确定他们从哪里获得
Id
值,但我想我可以了解一下您测试中的情况

首先,我认为你对什么是
假人感到困惑。如果是这样,别难过。他们可能会有点困惑。从

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

当FakeiTesy需要创建一个对象以提供给类构造函数时(我们将在后面看到更多),或者当它需要从方法或属性返回一个不可伪造的对象时,FakeiTesy本身通常会使用它们。最终用户很少需要创建它们

虚拟对象是一个实际的对象(必须是,否则,我们如何处理它?)。它必须具有其类型所具有的任何具体细节(在本例中,
ActionBlock
)。对虚拟泛型类型没有任何限制

查看的文档,我们可以看到,由于
ActionBlock
可能没有自定义的
idummDefinition
(您有吗?),而且它不是任务,也不可伪造(因为类是密封的),然后通过调用其中一个参数生成虚拟对象,并生成虚拟对象以满足每个参数

我猜ActionBlock有ID。我不知道它们是如何分配的,但是如果它们是一个好的ID,那么看起来我们有两个不同的
ActionBlock
s:一个在
区域提供。StartProgram
,以及测试中制作的假人

ActionBlocks文档表明它不会覆盖
Equals
,因此将执行引用比较,并且两个ActionBlocks(虚拟和生产代码中使用的一个)不匹配。这就是Fakeitesy无法识别调用的原因

如果您只是想看看是否使用第一个参数
null
和第二个参数some ActionBlock调用了
zone.ZoneProgram.Start
,我想您可能想使用:

A.CallTo(() => zone.ZoneProgram.Start(null, A<ActionBlock<InterruptInfo>>.Ignored))
            .MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(()=>zone.ZoneProgram.Start(空,如果您愿意的话)

这可能会让你克服眼前的问题,尽管我担心两件事:

  • 看起来
    zone.ZoneProgram.Start
    被调用了两次,而不是“确切地说。一次”,但我相信您能够处理这个问题,并且
  • 一般来说,伪造被测对象被认为是一种反模式。通常情况下,伪造被测产品代码的依赖关系会被视为一种反模式。我并不是说这不会起作用,但有时会导致混乱。不过,在当前问题解决后,这可能会成为下一天的问题
  • 我希望这有点帮助


    哦,你问了关于402问题。这个问题是关于在定义自定义类时给用户更多的权力,这些自定义类将控制如何创建假人。除非你创建了一个扩展
    IDummyDefinition
    DummyDefinition
    的类,否则在这一点上可能与此无关。

    谢谢你的详细回答。我没有回答意识到密封类不能像这样被模拟。所以我的后续问题是:从测试的角度来看,如何知道是使用虚拟类还是使用.Ignored技术?在这两种情况下,类型都是必需的,但对象的实际行为并不重要(引用您回复中的虚拟文档).至于你关于将被测对象伪装成反模式的观点,为什么会是这样?如果我们只是测试“管道”呢确保应该连接的部分通过方法调用连接起来?如何在不伪造对象的情况下进行测试?
    Ignored
    在传递给调用的参数无关紧要时使用。一般来说,对于调用匹配语义,技术是要使用的。一次虚拟构造的对象与任何其他对象一样,因此在
    A.CallTo
    中提供它意味着将使用
    Equals
    将其与实际参数进行比较。如果希望比较结果为“true”,那么你确实关心答案,所以虚拟是一个不好的选择。即使它碰巧起作用,也不清楚为什么。关于反模式,
    StartProgram
    调用
    ZoneProgram.Start
    ,这很好,但我们不知道
    ZoneProgram
    在这里是什么,就我所知,
    zone
    是由
    zone
    组成的说明。内部部件是连接的这一事实很重要,但只有对象才应该关心的事情我们通常关心外部可见的行为。检查内部管道通常只会使代码难以重构。当然,这只是一个指导原则。您可能有一个有效的案例可以通过这种方式进行测试,例如d如果没有全貌,也许我不应该评论。为了澄清,密封类可以是傻瓜。只是它们根本不是赝品。它们只是使用
    Activator.CreateInstance
    实例化的类的实例。
    A.CallTo(() => zone.ZoneProgram.Start(null, A<ActionBlock<InterruptInfo>>.Ignored))
                .MustHaveHappened(Repeated.Exactly.Once);