mosquito87
mosquito87

Reputation: 4440

Mocking a protected method always returning true

I have the following protected method in my base class:

protected bool ExecuteInteraction(string identifier,
    Action<object> interactionFinished, params object[] args)
{
    Contract.Requires(!string.IsNullOrEmpty(identifier));
    Contract.Requires(interactionFinished != null);

    bool result = false;

    if (!string.IsNullOrEmpty(identifier) && (interactionFinished != null))
    {
        // Find the matching interaction behavior.
        IInteractionBehavior interactionBehavior =
            InteractionBehaviorCollection.Instance.Get(identifier);

        if (interactionBehavior != null)
        {
            try
            {
                interactionBehavior.Execute(interactionFinished, args);
                result = true;
            }
            catch (Exception)
            {
            }
        }
        else
        {
            Debug.WriteLine(string.Format(
                "InteractionBehavior with identifier [{0}] is unknown",
                identifier));
        }
    }

    return result;
}

It's basically from this article: http://www.codeproject.com/Articles/708346/Dialogs-the-MVVM-Way ...

This method is used in my derived class like that:

protected override void Delete()
{
    try
    {
        if (PrimaryModel.Id != 0 && PrimaryModel.AddressId != 0)
        {
            ExecuteInteraction("DeleteConfirmation", (result) =>
            {
                MessageBoxResult messageBoxResult = (MessageBoxResult)result;

                if (messageBoxResult == MessageBoxResult.Yes)
                {
                    //Do something ...
                }
            });
        }
    }
    catch (Exception exc)
    {
        Message = exc.Message;
    }
}

This doesn't work in my unit test because I don't simulate that messageBoxResult is MessageBoxResult.Yes. This is the reason why I'd like my protected method to always returning true in the unit test. How can I do that (with moq)?

Upvotes: 0

Views: 307

Answers (2)

dymanoid
dymanoid

Reputation: 15227

I really suggest you to follow the concept explained by @Sheridan; but if you want to go your way, here is the solution how to mock a protected method:

Mock<YourBaseClass> baseClassMock = new Mock<YourBaseClass>();
baseClassMock.Protected().Setup<bool>(
    "ExecuteInteraction", 
     ItExpr.IsAny<string>(),
     ItExpr.IsAny<Action<object>>(),
     ItExpr.IsAny<object[]>())
.Returns(true);

Upvotes: 0

Sheridan
Sheridan

Reputation: 69987

You just need to interface your MessageBox actions so that you can provide a MockMessageBox when unit testing that always returns MessageBoxResult.Yes. So, in your code, don't reference any MessageBoxes directly. Create a WindowManager or MessageBoxService class that you call instead, kind of like a proxy message box.

For example, try something like this:

public string ShowMessageBox(string message, string title, string buttons, string icon)
{
    MessageBoxButton messageBoxButtons;
    switch (buttons.ToLower())
    {
        case "ok": messageBoxButtons = MessageBoxButton.OK; break;
        case "okcancel": messageBoxButtons = MessageBoxButton.OKCancel; break;
        case "yesno": messageBoxButtons = MessageBoxButton.YesNo; break;
        case "yesnocancel": messageBoxButtons = MessageBoxButton.YesNoCancel; break;
        default: messageBoxButtons = MessageBoxButton.OKCancel; break;
    }
    MessageBoxImage messageBoxImage;
    switch (icon.ToLower())
    {
        case "asterisk": messageBoxImage = MessageBoxImage.Asterisk; break;
        case "error": messageBoxImage = MessageBoxImage.Error; break;
        case "exclamation": messageBoxImage = MessageBoxImage.Exclamation; break;
        case "hand": messageBoxImage = MessageBoxImage.Hand; break;
        case "information": messageBoxImage = MessageBoxImage.Information; break;
        case "none": messageBoxImage = MessageBoxImage.None; break;
        case "question": messageBoxImage = MessageBoxImage.Question; break;
        case "stop": messageBoxImage = MessageBoxImage.Stop; break;
        case "warning": messageBoxImage = MessageBoxImage.Warning; break;
        default: messageBoxImage = MessageBoxImage.Stop; break;
    }
    return MessageBox.Show(message, title, messageBoxButtons, messageBoxImage).ToString();
}

This would be called like this:

string result = WindowManager.ShowMessageBox(message, title, "OkCancel", "Question");

Note how there are no direct relations to any UI dlls... all properties are string based. Now you need to interface the class that this method is in (WindowManager). So now we have an IWindowManager that forces us to write a ShowMessageBox method in all implementing classes.

Now we implement this interface in a MockWindowManager class:

public string ShowMessageBox(string message, string title, string buttons, string icon)
{
    switch (buttons)
    {
        case "Ok":
        case "OkCancel": return "OK";
        case "YesNo":
        case "YesNoCancel": return "Yes";
        default: return "OK";
    }
}

When running the application, we use the WindowManager class and when testing, we use the MockWindowManager class. This can be achieved in a number of ways, but the easiest is to pass an IWindowManager into the view model constructor:

public YourViewModel(IWindowManager windowManager)
{
    this.windowManager = windowManager;
}

Upvotes: 3

Related Questions