我在模拟带有(异步)方法的接口时遇到问题。接口看起来像这样:
public interface IDataAccessLayer
{
Task<bool> ExistsUserAsync(string username, CancellationToken cancellationToken);
Task<IUser> CreateUserAsync(string username, string password, DateTime dateOfBirth, CancellationToken cancellationToken);
}
..在那里的cancelestToken参数总是在运行时(通过NancyFx)以及在像这样的测试方法中模拟调用时从外部创建和传递的:
var validSignupRequest = new UserSignupRequest()
{
Username = "meh-spacey_space",
DateOfBirth = DateTime.Now.Subtract(TimeSpan.FromDays(365*35)),
Password = "someproper_passw*rd"
};
var testDataAccessLayer = A.Fake<IDataAccessLayer>(options => options.Strict());
var fakeUserInstance = A.Fake<IUser>();
A.CallTo(() => fakeUserInstance.Username).Returns(validSignupRequest.Username);
A.CallTo(() => testDataAccessLayer.ExistsUserAsync(validSignupRequest.Username, CancellationToken.None)).Returns(false); // works
A.CallTo(() => testDataAccessLayer.CreateUserAsync(validSignupRequest.Username, validSignupRequest.Password, validSignupRequest.DateOfBirth, CancellationToken.None)).Returns(fakeUserInstance); // does not work / throws ExpectationException
..对.ExistsUserAsync(...)的模拟调用确实起作用,.CreateUserAsync一个不起作用/抛出了ExpectationException。
我已经检查了正在测试的基础代码,并且使用与.CreateUserAsync(...)方法相同的值进行调用,并且我怀疑dateOfBirth是罪魁祸首,但至少.Ticks明智地是一模一样。
对于FakeItEasy如何执行签名/参数值匹配,我有点不确定,因为从理论上讲,调用IS是模拟的,但是FakeItEasy说不是。到目前为止,它是赢家。
有人知道我的方法模拟调用出了什么问题吗?
最佳答案
为了对这个问题有一个“答案”,这样新来的人就不必遍历评论和要旨,而不必弄清楚事情了,这是我对所发生事情的理解:
在原始问题中,电话
A.CallTo(() => testDataAccessLayer.CreateUserAsync(
validSignupRequest.Username,
validSignupRequest.Password,
validSignupRequest.DateOfBirth,
CancellationToken.None))
.Returns(fakeUserInstance);
不会抛出,但是稍后在执行生产代码并调用
testDataAccessLayer
时,未执行配置的方法-FakeItEasy不认为该调用与配置的匹配。这是因为在设置呼叫和实际呼叫之间,
DateOfBirth
最终被Jil序列化和反序列化,如this gist所示,并且DateTime失去了精度,因此参数不再相同。因此,FakeItEasy认为不需要拦截该呼叫。正如JörgB.在评论中提到的那样,FakeItEasy没有问题。它使用给出的数据正在尽力而为。
关于c# - FakeItEasy引发ExpectationException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26329057/