如何使用Moq存根接口方法 [英] How can I stub an interface method using Moq

查看:82
本文介绍了如何使用Moq存根接口方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种方法可以使用Moq存根方法?我看到了很多标题相似的问题,但没有一个能真正回答我的问题.这是给我的一个单元测试示例,我发现使用Moq进行测试非常困难.我想做的是对EmailTask​​s.UserIsValidForNotice()方法进行单元测试:

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

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

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

我知道这可能不是最好的设计,但是我只是想知道是否可以使用Moq来完成.

I understand that this might not be the best design, but I am just interested in if this can be done using Moq.

推荐答案

这里的问题是您要测试什么?

The question here is what are you testing?

IMO,您应该测试的是您是否使用正确的Func调用了存储库.您可以按照以下步骤进行操作:

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

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

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.

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

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

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

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.

这篇关于如何使用Moq存根接口方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆