Moq设置在被告知时没有返回值

本文关键字:返回值 设置 被告 Moq | 更新日期: 2023-09-27 18:02:03

我的测试场景是这样的:

var dbConnection = new Mock<IDbConnection>();
dbConnection.Setup(x => x.SearchFor<User>("users", y => y.Password =="12345" 
   && y.Username == "tester")).Returns(new List<User>{
       new User{
          Username = "tester",
           Password = "12345"
       }}.AsQueryable());
var users = new Users.Users(dbConnection.Object);
var user = users.Get("tester", "12345");

查看Get方法时:

public User Get(string username, string password){
    var total = _dbConnection.SearchFor<User>("users", y => 
        y.Password == password && 
        y.Username == username).Single();
    return total;
}

它应该根据我在网上找到的大多数样本工作,但它总是给我:

System.InvalidOperationException: Sequence contains no elements

当我把Get方法改成这样:

public User Get(string username, string password){
    var total = _dbConnection.SearchFor<User>("users", y => 
        y.Password == "12345" && 
        y.Username == "tester").Single();
    return total;
}

它神奇地工作,但get方法是在业务层,我们都知道…设置硬编码的用户名和密码是不好的。

问题是:我怎样才能让moq的设置正常工作?我做错了什么?

Moq设置在被告知时没有返回值

所以您正在设置,期望参数"users"y => y.Password == "12345" && y.UserName == "tester"。但是,第二个参数是lambda,很难比较(如果不是不可能的话?)当Moq检查你是否调用了那个时,它最终会比较lambda,这可能会失败。

例如,下面的代码显示了两个看似相同的函数,但它们不被认为是相等的:
Func<bool> a = () => true;
Func<bool> b = () => true;
(a == b).Dump(); //False
a.Equals(b).Dump(); //False

因此Moq不知道使用你设置的返回值。

您可能需要实现一个模拟存储库,它将实际运行lambda,而不是试图找到您提供的相同的存储库。

像这样:

class TestRepo
{
    public void Add<T>(T myType)
    {
        //add to an in-memory "database"
    }
    public IEnumerable<T> Get<T>(Expression<Func<T, bool>> filter)
    {
        return inMemoryDataBase.Where(filter);
    }
}

这将使您的Get方法看起来像这样:

public User Get(string username, string password){
    var total = RealRepo.Get<User>(y => 
        y.Password == "12345" && 
        y.Username == "tester").Single();
    return total;
}

和你的测试:

var repo = new TestRepo();
repo.Add(new User { Username = "tester", Password = "12345" });
var users = new Users.Users(dbConnection.Object);
var user = users.Get("tester", "12345");

这是一个有点相关的问题,用户试图找到一种唯一标识lambda的方法,以便可以按照您希望的方式对它们进行"比较"。我不知道有没有找到完美的解决方案。链接