Reputation: 4440
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
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
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 MessageBox
es 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