简体   繁体   English

如何使用Moq存根接口方法

[英]How can I stub an interface method using Moq

Is there a way to stub out a method using Moq? 有没有一种方法可以使用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. 这是给我的一个单元测试示例,我发现使用Moq进行测试非常困难。 What I would like to do is unit test the EmailTasks.UserIsValidForNotice() method: 我想做的是对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);
}

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. 我可以像下面那样建立一个存根,然后轻松地测试查询,但是由于无法访问Mocks Return函数中的方法参数,因此无法使用Moq进行查询。

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. 我知道这可能不是最好的设计,但是我只是想知道是否可以使用Moq完成。

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. IMO,您应该测试的是您是否使用正确的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. 当调用Verify方法时,您检查是否已调用存储库。 Furthermore you check whether it has been called with an instance of Func<User, bool> (that is the It.Is<> part. 此外,您检查是否已使用Func<User, bool>的实例(即It.Is<>部分) It.Is<>它。

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. 对于It.Is<>您可以指定一个回调函数,该回调函数将获取传递的参数,并在参数有效时返回true,否则返回false。 So in that callback you can execute the Func over a known user and check whether it evaluates correctly. 因此,在该回调中,您可以对已知用户执行Func并检查其评估是否正确。

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. 如果调用Returns的泛型重载,则最多可以指定8个类型参数。 The first ones will be passed in to the expression you provide (from the actual call) while the last one determines the return type. 第一个将被传递到您提供的表达式中(从实际调用中),而最后一个将确定返回类型。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM