Moq: неверный обратный вызов. Настройка метода с параметрами не может вызвать обратный вызов с параметрами

Я пытаюсь использовать moq для записи unit test. Вот мой код unit test

        var sender = new Mock<ICommandSender>();
        sender.Setup(m => m.SendCommand(It.IsAny<MyCommand>(), false))
              .Callback(delegate(object o)
              {
                  var msg = o as MyCommand;
                  Assert.AreEqual(cmd.Id, msg.Id);
                  Assert.AreEqual(cmd.Name, msg.Name);
              })
              .Verifiable();

SendCommand принимает объект и необязательный логический параметр. И MyCommand происходит от ICommand.

void SendCommand(ICommand commands, bool idFromContent = false);

Когда тест проходит, я вижу ошибку

System.ArgumentException : Invalid callback. Setup on method with parameters (ICommand,Boolean) cannot invoke callback with parameters (Object).

Я хочу проверить, является ли содержимое сообщения тем, что я отправил. Я искал форум и нашел пару различных вариантов этой проблемы, но это не помогло. Любая помощь приветствуется.

Ответ 1

Вам нужно вызвать общую перегрузку Callback с конкретными типами, ожидаемыми методом. Должно работать следующее:

sender.Setup(x => x.SendCommand(It.IsAny<MyCommand>(), false))
      .Callback<ICommand, bool>((command, idFromContent) =>
          {
              var myCommand = command as MyCommand;
              Assert.That(myCommand, Is.Not.Null);
              Assert.That(myCommand.Id, Is.EqualTo(cmd.Id));
              Assert.That(myCommand.Name, Is.EqualTo(cmd.Name));
          })
      .Verifiable();

Если утверждения не срабатывают в обратном вызове, тогда тест немедленно завершится, поэтому вызов Verifiable() (и, предположительно, последующий вызов Verify()) представляется избыточным. Если вы хотите разрешить посмеянный вызов отправки, даже если он не соответствует критериям, а затем проверить его после факта, вы можете сделать это вместо этого (после вызова метода проверки):

sender.Verify(x => x.SendCommand(It.Is<MyCommand>(c => 
    {
        Assert.That(c, Is.Not.Null);
        Assert.That(c.Id, Is.EqualTo(cmd.Id));
        Assert.That(c.Name, Is.EqualTo(cmd.Name));
        return true;
    }), false), Times.Once());