Home > other >  get text from windows form messagebox and close it dynamicly
get text from windows form messagebox and close it dynamicly

Time:11-22

I try to make unit tests for windows forms.Some forms have code showing messagebox.I want to test messagebox text and close the messagebox form from unit test.How can i make them ?

public partial class Form1 : Form
{
    private void Form1_Load(object sender, EventArgs e)
    {
        MessageBox.Show("Form opened");
    }
}

    [TestMethod]
    public void Form1_Load()
    {
        Form1 form = new Form1();
        //How to find messagebox to test TEXT and close the MESSAGEBOX form?
    }

CodePudding user response:

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

CodePudding user response:

My solution is like below.Thanks for sugesstions

public partial class Form1 : Form
{
    public Form1(){InitializeComponent();}
    internal bool is_Message_Show = true;
    internal string message_For_Test ;
    internal DialogResult dialogResult_From_Test;
    internal void btnAdd_Click(object sender, EventArgs e)
    {
        DialogResult result = DialogResult.No;
        if (is_Message_Show)
        {
            result = MessageBox.Show("Do you want to add", "WARNING", MessageBoxButtons.YesNo);
        }
        else
        {
            result = dialogResult_From_Test;
        }
        if (result == DialogResult.Yes)
        {
            
        }
    }

    internal void btnDelete_Click(object sender, EventArgs e)
    {
        string message = "Deleted";
        if (is_Message_Show)
        {
            MessageBox.Show(message);
        }
        else
        {
            message_For_Test = message;
        }
    }
}

    [TestMethod]
    public void btnAdd_Click_Yes()
    {
        Form1 form = new Form1();
        form.is_Message_Show = false;
        form.dialogResult_From_Test = System.Windows.Forms.DialogResult.Yes;
        form.btnAdd_Click(null, null);
        
    }
    [TestMethod]
    public void btnDelete_Click()
    {
        Form1 form = new Form1();
        form.is_Message_Show = false;
        form.btnDelete_Click(null, null);
        Assert.AreEqual("Deleted", form.message_For_Test);
    }
  • Related