采用Func <t>的模拟方法

时间:2016-06-20 07:44:46

标签: c# unit-testing moq

我试图在这个article

中做例子

有一个Generic存储库,它有一个像下面这样的Get方法。

public virtual TEntity Get(Func<TEntity, Boolean> where)
{
    return DbSet.Where(where).FirstOrDefault();
}

一种服务方法,通过使用存储库获取的用户名和密码对用户进行身份验证。

public int Authenticate(string username, string password)
{
    var user = _unitOfWork.UserRepository.Get(u => u.UserName == username && u.Password == password);

    if (user != null && user.UserId > 0)
    {
        return user.UserId;
    }
    return 0;
}

文章的作者模仿这个get方法,如下所示。

mockRepo.Setup(s => s.Get(It.IsAny<Func<User, bool>>()))
    .Returns((Func<User, bool> expr) => DataInitializer.GetAllUsers().Where(u => u.UserName == CorrectUserName)
            .FirstOrDefault(u => u.Password == CorrectPassword));

mockRepo.Setup(s => s.Get(It.IsAny<Func<User, bool>>()))
    .Returns((Func<User, bool> expr) => DataInitializer.GetAllUsers().Where(u => u.UserName == WrongUserName)
            .FirstOrDefault(u => u.Password == WrongPassword));

每次我打电话在我的测试中获取方法它会进行第二次模拟设置。并且它不会将参数视为用户名和密码。

[Test]
public void AuthenticateTest()
{

    var returnId = _userServices.Authenticate(CorrectUserName, CorrectPassword);
    var firstOrDefault = _users.Where(u => u.UserName == CorrectUserName).FirstOrDefault(u => u.Password == CorrectPassword);
    if (firstOrDefault != null)
        Assert.That(returnId, Is.EqualTo(firstOrDefault.UserId));
}

我如何模拟和测试这种Authenticate方法。

1 个答案:

答案 0 :(得分:6)

您的设置都引用相同的方法调用:

mockRepo.Setup(s => s.Get(It.IsAny<Func<User, bool>>()))

这会为通过任何Get的{​​{1}}的每次调用注册一个模拟方法。这与传递的函数的实际值无关。

由于两个设置都引用相同的调用,第二个设置将覆盖第一个,所以你实际上只有后一个。

如果要根据作为参数传递的值返回不同的内容,则有两种选择:要么更改设置以期望更明确的值(Func<User, bool>除外),要么更改返回函数以实际检查值。例如:

IsAny<T>

或者:

mock.Setup(x => x.DoSomething(2)).Returns(4);
mock.Setup(x => x.DoSomething(3)).Returns(9);

在您的情况下,您希望根据传递的lambda表达式更改返回值。这实际上有点复杂。最简单的可能是提供静态用户列表并在其上运行实际过滤器:

mock.Setup(x => x.DoSomething(It.IsAny<int>()).Returns(v => {
    if (v == 2)
        return 4;
    else
        return 9;
});