如何使用Moq存根接口方法

时间:2014-02-28 17:40:24

标签: c# unit-testing moq

有没有办法使用Moq存根方法?我看到了很多类似头衔的问题,但没有一个问题实际上回答了我的问题。这是我给出的单元测试示例,我发现使用Moq进行测试非常困难。我想做的是对EmailTask​​s.UserIsValidForNotice()方法进行单元测试:

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

我可以设置如下所示的存根,然后轻松测试查询,但我无法使用Moq,因为我无法访问Mocks Return函数中的方法参数。

public class StubRepo : IUserRepository
{
    public IList<User> PersonList { get; set; }

    public IList<User> FindAll(Func<User, bool> q)
    {
        return PersonList.Where(q).ToList();
    }
}

我知道这可能不是最好的设计,但我只是感兴趣,如果可以使用Moq完成。

2 个答案:

答案 0 :(得分:3)

这里的问题是你在测试什么?

IMO,您应该测试的是您是否使用正确的Func调用了存储库。你可以这样做:

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

调用Verify方法时,检查是否已调用存储库。此外,您检查是否已使用Func<User, bool>实例调用它 (即It.Is<>部分。

对于It.Is<>,您可以指定回调将获取传递的参数,并在参数有效时返回true,否则返回false。 因此,在该回调中,您可以对已知用户执行Func并检查它是否正确评估。

如果您仍想将其存根并返回某些内容,则可以这样做:

repoMock.Setup(r => r.FindAll(It.IsAny<Func<User, bool>>)
        .Returns<Func<User, bool>, IList<User>>(fnc => new List<User>());

如果调用Returns的泛型重载,则最多可以指定8个类型参数。第一个将传递给您提供的表达式(来自实际调用),而最后一个确定返回类型。

答案 1 :(得分:0)

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