6

I am writing a test case for my User Control which will prompt using MessageBox.Show for User Action asking to process or Cancel the operation. How can I design my unit test to mimic the User interaction to proceed?.

I do not want to refactor to move the logic to middle tier. This is a simple case of getting User Consent and proceeding with middle tier call. Any help/ideas restructuring UI for this scenario will also be helpful.

1
  • So you want to test what your control does when they click each of these? or the test itself has a blocking messagebox dialog to see if the middle tier is safe to test? Commented Jan 8, 2010 at 16:56

3 Answers 3

7

Clicking a button is nothing else than invoking the corresponding click event. So you might want to build your test around that.

Even better (if this isn't the case yet), move your code out of the frontend, and build your unittests around the business actions, you'd otherwise invoke by clicking a button.

update after edit by author
You are not going to get this to work as long as you are not prepared to split things, you cannot build your unit tests around 'click here', 'click there'. Imagine the following code:

private int MyFunction()
{
    bool insideVariable = false;
    if(insideVariable) 
        return 1;
    else
        return 2;
}

You will never be able to unit test the case where insideVariable is set to true; You can either:

  1. Refactor your code so the return 1 statement is somewhere in your middle tier
  2. Refactor so that the return 1 statement is a method in your GUI. You can then test that function.

Application frontends should be quite easily to replace, so no business logic should be stored in there. Unit tests are just another frontend living next to your main GUI.

Sign up to request clarification or add additional context in comments.

4 Comments

I can use SendKeys.SendWait similar stuff, but the problem here is ShowDialog is a blocking call
You shouldn't try to do really clicking the button, but just something like new Form1().Button1_Click(this, null).
+1 - If the UI holds enough logic that duplicating its action requires actually using the UI code, then the UI contains too much logic. It might be worth noting exceptions - presentation logic is always tricky in this regard - but in general testable code doesn't live in the UI to begin with.
@Jan. I have edited my question. Basically I am using a simple MessageBox.Show (not a Form.ShowDisalog as I had mistakenly stated before). This is the blocking code. I don't think Form1().Button1_Click(this, null) will work here.
4

Providing a solution would be much easier with the UI method or related methods posted. Also seeing the TestMethod(s) could help even incomplete methods.

If I understand your test purpose is to determine what happens on the different click possibilities?

You could set up your actual method that triggers the MessageBox using Inversion of Control and Dependency Injection like this:

public class ClassUnderTest
{
    private static Func<string, string, MessageBoxButtons, DialogResult>
       _messageBoxLocator = MessageBox.Show;
    public static Func<string, string, MessageBoxButtons, DialogResult> 
       MessageBoxDependency
    {
        get { return _messageBoxLocator; }
        set { _messageBoxLocator = value; }
    } 

    private void MyMethodOld(object sender, EventArgs e)
    {
        if (MessageBox.Show("test", "", MessageBoxButtons.YesNo) == 
            System.Windows.Forms.DialogResult.Yes)
        {
            //Yes code
            AnsweredYes = true;
        }
        else
        {
            //No code

        }
    }

    public bool AnsweredYes = false;

    public void MyMethod(object sender, EventArgs e)
    {
        if (MessageBoxDependency(
                    "testText", "testCaption", MessageBoxButtons.YesNo) 
            ==
            System.Windows.Forms.DialogResult.Yes)
        {
            //proceed code
            AnsweredYes = true;
        }
        else
        {
            //abort code
        }


    }
}

and then the test method (remember to include the using Microsoft.VisualStudio.TestTools.UnitTesting; at the top) would be like this:

[TestMethod]
    public void ClassUnderTest_DefaultAnsweredYes_IsFalse()
    {
        var classUnderTest = new ClassUnderTest();
        Assert.AreEqual(false, classUnderTest.AnsweredYes);
    }
    [TestMethod]
    public void MyMethod_UserAnswersYes_AnsweredYesIsTrue()
    {
        //Test Setup
        Func<string, string, MessageBoxButtons, DialogResult> 
            fakeMessageBoxfunction =
                    (text, caption, buttons) =>
                    DialogResult.Yes;

        //Create an instance of the class you are testing
        var classUnderTest = new Testing.ClassUnderTest();
        var oldDependency = Testing.ClassUnderTest.MessageBoxDependency;
        Testing.ClassUnderTest.MessageBoxDependency = fakeMessageBoxfunction;
        try
        {
            classUnderTest.MyMethod(null, null);
            Assert.AreEqual(true, classUnderTest.AnsweredYes);
            //Assert What are you trying to test?
        }
        finally
        { //Ensure that future tests are in the default state
            Testing.ClassUnderTest.MessageBoxDependency = oldDependency;
        }
    }

Comments

0

Maybe we can try UI Automation which is officially from Microsoft? https://msdn.microsoft.com/en-us/library/aa348551.aspx

1 Comment

Make this a comment please.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.