2

I have this in my test scenario:

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

When looking at the Get method:

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

It should work according by most of the samples I found on the internet, but it always gives me:

System.InvalidOperationException: Sequence contains no elements

When I change my Get method to this:

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

It magicaly works, but the get method is in a business layer and like we all know... to set a username and password hardcoded is never good.

The question is: How can I get the setup for moq work properly? What am I doing wrong?

M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118

1 Answers1

0

so you're setting up, expecting the paramters "users" and y => y.Password == "12345" && y.UserName == "tester". However, your second parameter is a lambda, which are hard to compare (if not impossible?). So, when Moq is checking to see if you've called that, it's ultimately trying to compare lambdas, which will probably fail.

For example the following code shows two seemingly identical functions, but they are not considered to be equal:

Func<bool> a = () => true;
Func<bool> b = () => true;
(a == b).Dump(); //False
a.Equals(b).Dump(); //False

Therefore Moq doesn't know to use the return value that you setup.

You may need to implement a mock repository that will actually run the lambda instead of trying to find the same one that you provided.

Something like this:

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

Which would make your Get method look something like this:

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

And your test:

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

Here is a somewhat related question where a user was trying to find a way to uniquely identify a lambda so that they could be "compared" in the way you're hoping for. I don't know that any perfect solutions were found there. Link

Community
  • 1
  • 1
DLeh
  • 23,806
  • 16
  • 84
  • 128