为什么我不能在变量中捕获 FakeItEasy 期望值?

Why can't I capture a FakeItEasy expectation in a variable?

我正在使用 FakeItEasy 伪造一些 Entity Framework 调用,以确保正确映射一堆奇怪的遗留数据库表。

我需要断言正在将发票与特定 DeliveryAddress 匹配的客户添加到数据库中。

如果我这样做:

A.CallTo(() => db.Customers.Add(
    A<Customer>.That.Matches(
        c => c.Invoices.First().Address == EXPECTED_ADDRESS)
    )
)).MustHaveHappened();

代码完美运行。我想通过将期望移到别处来简化语法,但是当我这样做时:

var expected = A<Customer>.That.Matches(
    c => c.Invoices.First().Address == EXPECTED_ADDRESS)
);
A.CallTo(() => db.Customers.Add(expected)).MustHaveHappened();

测试失败。 FakeItEasy 代码内部发生了什么,这意味着期望表达式在内联时有效,但不能在变量中捕获并在以后重用?

不能直接回答为什么期望表达式内联起作用,但不能在变量中起作用(我正在研究它,将很快编辑答案!)

不过,我不是.That.Matches

的粉丝

如果有多个火柴,火柴会变得有点笨拙。另外,如果 any 匹配失败,MustHaveHappened 调用将抛出异常。让我不知道失败发生在哪里。

我更喜欢这样做:

Customer addedCustomer;
A.CallTo(() => a.Add(A<Customer>._))
    .Invokes(c => addedCustomer = c.GetArgument<Customer>(0));

//Individual Asserts on addedCustomer
Assert.AreEqual(EXPECTED_ADDRESS, addedCustomer.Invoices.First().Address);

答案在文档中 Always place Ignored and That inside A.CallTo:

The Ignored (and _) and That matchers must be placed within the expression inside the A.CallTo call. This is because these special constraint methods do not return an actual matcher object. They tell FakeItEasy how to match the parameter via a special event that's fired then the constraint method is invoked. FakeItEasy only listens to the events in the context of an A.CallTo.

不过 "test fails" 令我感到惊讶。您使用的是什么版本?从 FIE 2.0.0 开始,使用 That 就像 should throw an exception 一样

System.InvalidOperationException : A<T>.Ignored, A<T>._, and A<T>.That
can only be used in the context of a call specification with A.CallTo()

布莱尔的回答是正确的。我只想提出一个解决方法:

// Local function, requires C# 7
Customer ExpectedCustomer() =>
    A<Customer>.That.Matches(
        c => c.Invoices.First().Address == EXPECTED_ADDRESS));

A.CallTo(() => db.Customers.Add(ExpectedCustomer())).MustHaveHappened();