采用 Func<T> 的模拟方法

Mocking method that takes Func<T>

我正在尝试在此 article

中做示例

有一个通用存储库具有如下所示的 Get 方法。

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

以及使用存储库 Get 通过用户名和密码对用户进行身份验证的服务方法。

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));

每次我在测试中调用 Get 方法时,它都会进行第二次模拟设置。并且它不将参数视为用户名和密码。

[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 方法。

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

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

这将为每个传递 Func<User, bool>Get 调用注册一个模拟方法。这与传递的函数的实际值无关。

由于两个设置都引用同一个调用,第二个设置将覆盖第一个,因此您实际上只有后一个。

如果您想 return 根据作为参数传递的值进行不同的设置,您有两种选择:要么更改设置以期望更明确的值(除了 IsAny<T>),或者您更改 return 函数以实际检查该值。例如:

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

或者:

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

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

mockRepo.Setup(s => s.Get(It.IsAny<Func<User, bool>>())).Returns(expr => {
    User[] users = new User[] {
        new User { UserName = CorrectUserName, Password = CorrectPassword },
        new User { UserName = WrongUserName, Password = "foobar" },
    };
    return users.Where(expr).FirstOrDefault();
});