【问题标题】:Mocking a Method that uses an Optional Parameter using Moq使用 Moq 模拟使用可选参数的方法
【发布时间】:2016-09-21 14:35:25
【问题描述】:

我有一个消息框服务,具有以下界面

public interface IMessageBoxService
{
    DialogResult DisplayMessage(IWin32Window owner, string text,
        string caption, MessageBoxButtons buttons, MessageBoxIcon icon,
        MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1);
}

它本质上包装了System.Windows.Forms 消息框,并允许我模拟显示消息框的部分代码。现在我有一个文本文档的搜索服务,如果搜索循环,它会显示“不再出现”消息。我想为这个类的功能写一个单元测试,FindNextMethod

public TextRange FindNext(IDocumentManager documentManager, IMessageBoxService messageBoxService, 
        TextEditorControl textEditor, SearchOptions options, FindAllResultSet findAllResults = null)
{
    ...
    if (options.SearchType == SearchType.CurrentDocument)
    {
        Helpers.SelectResult(textEditor, range);
        if (persistLastSearchLooped)
        {
            string message = MessageStrings.TextEditor_NoMoreOccurrances;
            messageBoxService.DisplayMessage(textEditor.Parent, message,
                Constants.Trademark, MessageBoxButtons.OK, MessageBoxIcon.Information); <- Throws here.
            Log.Trace($"TextEditorSearchProvider.FindNext(): {message}");
            lastSearchLooped = false;
        }
    }
    ...
}

我的测试是

[TestMethod]
public void FindInCurrentForwards()
{
    // Mock the IMessageBoxService.
    int dialogShownCounter = 0;
    var mock = new Mock<IMessageBoxService>();
    mock.Setup(m => m.DisplayMessage(It.IsAny<IWin32Window>(), It.IsAny<string>(), It.IsAny<string>(), 
        It.IsAny<MessageBoxButtons>(), It.IsAny<MessageBoxIcon>(), It.IsAny<MessageBoxDefaultButton>()))
         .Returns(DialogResult.OK)
         .Callback<DialogResult>(r =>
            {
                Trace.WriteLine($"MockMessageBoxService {r.ToString()}");
                dialogShownCounter++;
            });

    // Start the forward search through the first document.
    var options = new SearchOptions()
    {
        SearchText = "SomeText",
        SearchType = SearchType.CurrentDocument,
        MatchCase = false,
        MatchWholeWord = false,
        SearchForwards = false
    };
    var searchProvider = new TextEditorSearchProvider();
    var textEditor = ((TextEditorView)documentManager.GetActiveDocument().View).TextEditor;

    TextRange range = null;
    for (int i = 0; i < occurances + 1; ++i)
        range = searchProvider.FindNext(documentManager, mock.Object, textEditor, options);

    // We expect the text to be found and the dialog to be displayed once.
    Assert.IsNotNull(range);
    Assert.AreEqual(1, dialogShownCounter);
}

但是我得到了一个

System.Reflection.TargetParameterCountException 参数计数不匹配。

我已经看到了这个question,我似乎按照答案的建议提供了可选参数,但我仍然遇到异常,为什么?

我看到了一个answer here 建议我必须使用具有正确参数计数的.Result,所以我尝试了

mock.Setup(m => m.DisplayMessage(It.IsAny<IWin32Window>(), It.IsAny<string>(), It.IsAny<string>(), 
        It.IsAny<MessageBoxButtons>(), It.IsAny<MessageBoxIcon>(), It.IsAny<MessageBoxDefaultButton>()))
    .Returns((IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon,
            MessageBoxDefaultButton defaultButton) => DialogResult.OK)
    .Callback<DialogResult>(r =>
            {
                Trace.WriteLine($"MockMessageBoxService {r.ToString()}");
                dialogShownCounter++;
            });

感谢您的宝贵时间。

【问题讨论】:

    标签: c# unit-testing moq


    【解决方案1】:

    TargetParameterCountException 被抛出是因为你的回调注册只注册了一个参数。

    .Callback<DialogResult>(r =>
            {
                Trace.WriteLine($"MockMessageBoxService {r.ToString()}");
                dialogShownCounter++;
            });
    

    回调不能接受 Returns 返回的值。它仍然必须匹配模拟的方法签名。

    .Callback((IWin32Window a1, string a2,
        string a3, MessageBoxButtons a4, MessageBoxIcon a5,
        MessageBoxDefaultButton a6) => { dialogShownCounter++ });
    

    【讨论】:

    • 非常感谢您的回答。最受赞赏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 2011-01-12
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-17
    相关资源
    最近更新 更多