Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a Method that uses an Optional Parameter using Moq

I have a message box service that hase the following interface

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

It essentally wraps the System.Windows.Forms message box and allows me to Mock parts of my code that show a message box. Now I have a search service for text documents that shows a "No more occurrances located" message if the search looped. I want to write a unit test for the functionality of this class, the FindNextMethod is

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

My test is

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

However I am getting an

System.Reflection.TargetParameterCountException Parameter count mismatch.

I have seen this question and I seem to be doing as the answer suggest and supplying the optional parameter but I still get the exception, why?

I have seen an answer here suggesting I have to use .Result with the correct parameter count, so I tried

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

Thanks for your time.

like image 777
MoonKnight Avatar asked May 24 '16 11:05

MoonKnight


People also ask

How do you mock a method in Moq?

First, we instantiate the FakeDbArticleMock class and indicate which setup we want to use for this test. Then, it is necessary to instantiate the repository we want to test and inject the mock instance into it. Finally, we call the method we are testing and assert the results.

What can be mocked with Moq?

Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation. Moq is a mock object framework for .

Can you mock a class with Moq?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can't be static or sealed, and the method being mocked should be marked as virtual.

What is optional parameter in C# with example?

A method that contains optional parameters does not force to pass arguments at calling time. It means we call method without passing the arguments. The optional parameter contains a default value in function definition. If we do not pass optional argument value at calling time, the default value is used.

When are optional parameters not optional in Moq?

Optional parameters aren’t optional when you’re using Moq. When you’re setting up or verifying a method call on a mock object, and the method has an optional parameter that you didn’t specify a value for, you’ll get the following compiler error: Error CS0854 – An expression tree may not contain a call or invocation that uses optional arguments

How to configure method calls on Moq mocks?

Additionally, developers can configure sequences of calls. Finally, Moq supports the configuration of methods with less common arguments such as reference parameters, out parameters and optional arguments. Using the Setup method, developers can configure method calls on mocks by leveraging the different argument match techniques shown earlier.

What is the use of MoQ in Java?

Most of the times, Moq will be used to mock service interfaces and their methods. Moq offers several utilities to properly configure method calls. As shown earlier, methods can be configured using the Setup method. Additionally, developers can configure sequences of calls.

How do I get the parameter passed to a mock method?

When you’re using Moq to set up a mocked method, you can use Callback () to capture the parameters passed into the mocked method: string capturedJson; mockRepo.Setup (t => t.Save (It.IsAny<string > ())) .Callback ( (string json) => { Console.WriteLine ("Repository.Save (json) called.


Video Answer


1 Answers

The TargetParameterCountException is thrown because your callback registration is only registered with one parameter.

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

The Callback cannot accept the value returned by Returns. It still has to match the mocked method signature.

.Callback((IWin32Window a1, string a2,
    string a3, MessageBoxButtons a4, MessageBoxIcon a5,
    MessageBoxDefaultButton a6) => { dialogShownCounter++ });
like image 141
Adam B Avatar answered Oct 17 '22 08:10

Adam B