如何使用Moq验证多个方法调用

时间:2011-06-08 02:22:19

标签: c# testing .net-4.0 mocking moq

所以场景是这样的:用户做了一些动作(比如赚取徽章或解锁某些东西),并发送电子邮件通知。一个给用户(有一条消息,比如“你已解锁XYZ ......”),然后向他们的每个朋友发送一条不同的消息(“你的朋友已解锁XYZ ......”)。

public interface INotify
{
   void Notify(User user, User friend);
}

public class NotificationService
{
    private IEnumerable<INotify> _notifiers;

    public NotificationService(IEnumerable<INotify> notifiers)
    {
        _notifiers = notifiers;
    }

    public SendNotifications()
    {
        User user = GetUser();
        IEnumerable<User> friends = GetFriends();

        foreach(var notifier in _notifiers)
        {
            //Send notification to user
            notifier.Notify(user, null);

            //send notification to users friends
            foreach(var friend in friends)
                notifier.Notify(user, friend);
        }
    }
}

我正在尝试使用moq测试每个通知程序被称为2x。将null作为第二个参数传递,第二次将值传递给两个参数。

[Test]
public void MakeSureEveryoneIsNotified()
{
     var notifierMock = new Mock<INotifier>();

     var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });    
     svc.SendNotifications();

     notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), null), Times.Once());
     notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), It.Is<User>(user => user.UserId == 2)), Times.Once());
}

问题是第二个验证调用会为第二个参数抛出ArgumentNullException。有没有说“检查第一个呼叫有这些参数,然后第二个呼叫有其他参数”。我知道我可以通过调用:

来解决它
notifierMock.Verify(x => x.Notify(It.IsAny<User>(), It.IsAny<User>()), Times.Exactly(2));

但我想要更具体一点。无论如何要做到这一点?

2 个答案:

答案 0 :(得分:23)

您可以通过记录每次拨打Notify时发生的事情来实现此目的。然后,您可以将录音与预期进行比较:

[TestMethod]
public void TestMoqInvocations()
{
    var notifierMock = new Mock<INotifier>();

    var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });    
    svc.SendNotifications();

    var invocations = new List<NotifyParams>();

    notifierMock
        .Setup(f => f.Notify(It.IsAny<User>(), It.IsAny<User>()))
        .Callback<string, string>((user, friend) => invocations.Add(new NotifyParams{user = user, friend = friend}));

    Assert.AreEqual(1, invocations[0].user.UserId);
    Assert.IsNull(invocations[0].friend);
    Assert.AreEqual(1, invocations[1].user.UserId);
    Assert.AreEqual(2, invocations[1].user.UserId);
}

public struct NotifyParams { 
    public User user {get;set;}
    public User friend { get; set; }
}

答案 1 :(得分:0)

您可以创建获取用户列表的方法。然后通过It.Is方法获取用户。

private bool GetUser(User user, List<User> users)
{
    if (user != null)
        users.Add(user);

    return true;
}
[Test]
public void MakeSureEveryoneIsNotified()
{
     var notifierMock = new Mock<INotifier>();

     var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });    
     svc.SendNotifications();

     var users = new List<User>();
     var friends = new List<User>();

     // verify how many times call the method
     notifierMock
        .Verify(x => x.Notify(
            It.Is<User>(u => GetUser(u, users)), 
            It.Is<User>(f => GetFriend(f, friends))
        ), Times.Exactly(2));

    Assert.AreEquals(2, users.Count);
    Assert.AreEquals(1, users[0].UserId);
    Assert.AreEquals(1, users[1].UserId);

    Assert.AreEquals(1, friends.Count);
    Assert.AreEquals(2, friends[0].UserId);
}