I'm using FakeItEasy to fake some Entity Framework calls, to make sure a bunch of weird legacy database tables are getting mapped properly.
I need to assert that a Customer with an Invoice matching a specific DeliveryAddress is being added to the database.
If I do this:
A.CallTo(() => db.Customers.Add(
A<Customer>.That.Matches(
c => c.Invoices.First().Address == EXPECTED_ADDRESS)
)
)).MustHaveHappened();
the code works perfectly. I want to streamline the syntax by moving the expectation elsewhere, but when i do this:
var expected = A<Customer>.That.Matches(
c => c.Invoices.First().Address == EXPECTED_ADDRESS)
);
A.CallTo(() => db.Customers.Add(expected)).MustHaveHappened();
The test fails. What is happening inside the FakeItEasy code that means the expectation expression works when it's inline but can't be captured in a variable and reused later?
The answer is in the docs at Always place Ignored and That inside A.CallTo:
The
Ignored
(and_
) andThat
matchers must be placed within the expression inside theA.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 anA.CallTo
.
I'm surprised the "test fails", though. What version are you using? As of FIE 2.0.0, using That
as you did should throw an exception like
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()
Not a direct answer for why the expectation expression works inline, but not in a variable (I'm working on that, will edit answer shortly!)
However, I'm not a fan of .That.Matches
The matches can get a bit unwieldy if there's more than one. Plus the MustHaveHappened
call will throw an exception if any of the matches fail. Leaving me no idea where the failure happened.
I prefer to do this:
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);
Blair's answer is correct. I just want to suggest a workaround:
// 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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With