How can I stub an interface method using Moq

时间秒杀一切 提交于 2019-12-08 01:18:33

问题


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.


回答1:


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.




回答2:


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


来源:https://stackoverflow.com/questions/22102120/how-can-i-stub-an-interface-method-using-moq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!