Reputation: 2178
Is there a way to stub out a method using Moq? I saw quite a few questions with similar titles, but none that actually answered my question. Here was a unit testing example I was given and I found it very difficult to test using Moq. What I would like to do is unit test the EmailTasks.UserIsValidForNotice() method:
public class User
{
public DateTime JoinDate { get; set; }
public bool Active { get; set; }
}
public class EmailTasks
{
IUserRepository repo;
public EmailTasks(IUserRepository repo)
{
this.repo = repo;
}
public IList<User> UserIsValidForNotice(DateTime minDate)
{
return repo.FindAll(u => u.Active && u.JoinDate > minDate);
}
}
public interface IUserRepository
{
IList<User> FindAll(Func<User, bool> q);
}
I can set up a stub like the following and then easily test the query, but I was not able to do it using Moq, because I couldn't access the method parameters in Mocks Return function.
public class StubRepo : IUserRepository
{
public IList<User> PersonList { get; set; }
public IList<User> FindAll(Func<User, bool> q)
{
return PersonList.Where(q).ToList();
}
}
I understand that this might not be the best design, but I am just interested in if this can be done using Moq.
Upvotes: 2
Views: 3631
Reputation: 2773
var personList = new List<User>(); // set up your personList here
var repoMock = new Mock<IUserRepository>();
repoMock.Setup(repo => repo.Findall(It.IsAny<Func<User, bool>>())
.Return((Func<user, bool> q) => personList.Where(q).ToList());
Upvotes: 0
Reputation: 28737
The question here is what are you testing?
IMO, what you should be testing is whether you have called the repository with the correct Func. You could do this as follows:
[Test]
public void UserIsValidForNotice_has_correct_expression()
{
var repoMock = new Mock<IUserRepository>();
var sut = new EmailTasks(repoMock.Object);
sut.UserIsValidForNotice(DateTime.Now);
repoMock.Verify(r => r.FindAll(It.Is<Func<User, bool>>(func => func(someUser));
}
When you call the Verify method, you check whether the repository has been called. Furthermore you check whether it has been called with an instance of Func<User, bool>
(that is the It.Is<>
part.
For It.Is<>
you can specify a callback will get the parameter that was passed and returns true when the parameter was valid and false if not.
So in that callback you can execute the Func
over a known user and check whether it evaluates correctly.
If you still want to stub it out and return something, you could do it like this:
repoMock.Setup(r => r.FindAll(It.IsAny<Func<User, bool>>)
.Returns<Func<User, bool>, IList<User>>(fnc => new List<User>());
If you call the generic overload of Returns
you can specify up to 8 type parameters. The first ones will be passed in to the expression you provide (from the actual call) while the last one determines the return type.
Upvotes: 3