我在使用(异步)方法模拟接口(interface)时遇到问题。界面如下所示:
public interface IDataAccessLayer
{
Task<bool> ExistsUserAsync(string username, CancellationToken cancellationToken);
Task<IUser> CreateUserAsync(string username, string password, DateTime dateOfBirth, CancellationToken cancellationToken);
}
.. 上面的 cancellationToken 参数总是在运行时(通过 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 一个不有效/抛出一个期望异常。
我已经检查了正在测试的底层代码,并且正在使用与 .CreateUserAsync(...) 方法相同的值进行调用,我怀疑 dateOfBirth 是罪魁祸首,但至少 .Ticks明智的是完全一样。
我有点不确定 FakeItEasy 如何执行签名/参数值匹配,因为理论上调用是模拟的,但 FakeItEasy 说不是。到目前为止它正在获胜..
有人知道我的方法模拟调用有什么问题吗?
最佳答案
为了对这个问题有一个“答案”,这样新手就不必通过评论和要点以及诸如此类的东西来解决问题,这是我对发生的事情的理解:
在原题中,调用
A.CallTo(() => testDataAccessLayer.CreateUserAsync(
validSignupRequest.Username,
validSignupRequest.Password,
validSignupRequest.DateOfBirth,
CancellationToken.None))
.Returns(fakeUserInstance);
不抛出,但后来当执行生产代码并调用 testDataAccessLayer
时,配置的方法没有执行——FakeItEasy 认为调用不匹配配置的内容。
这是因为在设置调用和实际调用之间,DateOfBirth
最终被 Jil 序列化和反序列化。 ,如图this gist ,并且 DateTime 失去精度,因此参数不再相同。因此,FakeItEasy 认为没有必要拦截调用。
正如 Jörg B. 在评论中提到的,FakeItEasy 没有问题。它正在根据提供的数据尽力而为。
关于c# - FakeItEasy 抛出 ExpectationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26329057/