I think you don't want to test the functionality of a MessageBox, after all, that is a windows method. You'll have to trust Microsoft that they have tested this class.
What you do want to test, is that when your form loads, that it shows some information to the operator. You want to hide that this is done using a MessageBox. This has the advantage that you can reuse this method if you want other methods to show something to the operator.
Another advantage: you can also change how things are shown to the operator, without having to change all users of the method. For instance, if you want to sound a beep when you warn the operator, or maybe you want to log that the operator has confirmed reading the warning. If you do this in a separate method, you don't have to change all users of this method.
In other words: your form has an OperatorInformer object (TODO: invent a proper name). This object implements an interface:
interface IOperatorInformer
{
void ShowMessage(string text, ...);
void ShowWarning(string text, ...);
void ShowError(string text, ...);
...
}
If you need to be language aware, consider to create an enum with all warnings and errors. The interface will be:
enum OperatoInformationId {...}
interface IOperatorInformer
{
void InformOperator(OperatorInformationId id, ...);
...
}
It is the task of the OperatorInformer to convert the OperationInformationId into the proper text,
class OperatorInformer : IOperatorInformer
{
...
public static IOperatorInformer Default {get;} = new OperatorInformer;
}
This OperatorInformer can use the MessageBox.Show
to show the desired text, with the desired icons, sounds, header etc.
This won't solve the problem of testing that the MessageBox is shown, but as this is a small class, chances to make errors are small. If you really need to test the OperatorInformer, consider to do the same with interface IMessageBox
, which will define the MessageBox methods, and a class MessageBox
, which will use System.Windows.Forms.MessageBox
to display messages.
class Form1 : Form
{
// make sure there is always at least the default operator informer:
public IOperatorInformer OperatorInformer {get; set;} = OperatorInformer.Default();
...
}
Unit test method Form1_Load
After you defined interface IOperatorInformer, you can change your requirements:
Requirement: When Form1 Loads, method IOperatorInformer.ShowMessage
is called exactly once with a text "Form opened", an icon ... and a title bar ...
This is way more easy to unit test:
class UnitTestInformer : IOperatorInformer
{
public int CallCount {get; private set;} = 0;
public string Text {get; private set;}
public MessageBoxIcon Icon {get; private set;} = MessageBoxIcon.None;
...
public void ShowMessage(string text, MessageBoxIcon icon, ...)
{
++this.CallCount;
this.Text = text,
this.Icon = icon,
...
}
}
Your unit tests (every test tests exactly one thing from the requirements)
[TestMethod]
public void Form1_Load_ShowsOperatorInputExactlyOnce()
{
// Create a unitTestInformer and a Form1 that uses this UnitTestInformer
UnitTestInformer unitTestInfomer = new UnitTestInformer();
Form1 form = new Form1()
{
OperatorInformer = unitTestInformer;
};
form.Show(); // this should Load the form
Assert.AreEqual(1, unitTestInformer.CallCount);
}
[TestMethod]
public void Form1_Load_OperatorInputText()
{
UnitTestInformer unitTestInfomer = new UnitTestInformer();
Form1 form = new Form1()
{
OperatorInformer = unitTestInformer;
};
form.Show();
Assert.AreEqual("Form opened", unitTestInformer.Text);
}
etc. Also unit tests for Icon and Title bar