Как проверить несколько вызовов методов с Moq - PullRequest
20 голосов
/ 08 июня 2011

Таким образом, сценарий таков: пользователь выполняет какое-то действие (например, зарабатывает значок или что-то разблокирует), и отправляется уведомление по электронной почте.Одно для пользователя (с сообщением типа «Вы разблокировали 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));

Но я хотел быть более конкретным.В любом случае, чтобы сделать это?

1 Ответ

23 голосов
/ 08 июня 2011

Этого можно добиться, записав, что происходит при каждом вызове, на 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; }
}
...