This article describes how to write an automated user interface test framework based on Ranorex (a GUI automation framework supporting .NET). The test framework should give testers the ability to easily check the features of an application. The Calculator application is used as dummy program for an application being tested.

Please notice that this blog post targets Ranorex 1.X and might be obsolete if you use Ranorex 2.x or newer!”

Why automating the user interface?

Unit testing or test-driven development help recognition of most bugs at development time, but these test methodologies can’t find bugs in the user interface. Users usually interact with an application using its GUI. Manual testing of GUI applications is time consuming and testers have to be patient and go through recurring test cases over and over again. Moreover a framework gives the possibility to combine GUI simulation and test validation. To elimenate high costs from manual testing, basic functionality of GUI programs should be tested.

Concept of a Test Automation Framework

First of all, concentrate on the base functionality of your application. Decide what you want to test. The illustration below shows how the components of the automation test framework will interact: GUI Test Automation Framework The Test Automation Framework consists of a CalcGUITesterClass and several test scripts. The CalcGUITesterClass performs the main part. This class will offer a wide range of functionality for the testers.

Calculator GUI Tester Class

This class provides an easy to use interface on which testers can build their test cases. The Calculator GUI Tester class interacts through Ranorex with the external application (Calculator) and runs user interface operations like clicking buttons, moving the mouse and simulating keystrokes. The methods and properties are similar to the internal functionality of the tested application (e.g. Add(num1, num2)). They simulate GUI actions (as a user would perform them) and check the results. There are two big advantages in writing a wrapper class for the application under test:

  • Test code is clear and easy to maintain
  • Test code is (more) independent from the application under test

That means after a new version release some elements of the user interface may change. After updating the wrapper (CalcGUITesterClass) the test scripts should work without the need for any changes.

Constructor and Destructor

There are several ways to find an application with Ranorex:

  • by its title (e.g. Calculator)
    	Form form = Application.FindFormTitle("Calculator");
  • by its class name (e.g. SciCalc)
  • 	Form form = Application.FindFormClassName("SciCalc");

Use the RanorexSpy to analyze your application. The following constructor is used to find the tested application (Calculator) or starts it if not already running. After completing the test case, the tested application will be closed in the destructor.

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using Ranorex;

namespace CalcGUITester
{
    public class CalcGUITesterClass
    {
        // Note: Application, Form, Menu and Mouse classes
        //       belong to the Ranorex namespace
        Form form;
        Menu menu;

        public CalcGUITesterClass()
        {
            try
            {
                form = Application.FindFormClassName("SciCalc");
            }
            catch (ControlNotFoundException e)
            {
                Application.Start("calc");
                Application.Sleep(200);
                form = Application.FindFormClassName("SciCalc");
            }

            menu = new Menu(form);
        }

        ~CalcGUITesterClass()
        {
            form.Close();
        }

    }
}

Methods

The Add(num1, num2) method automates the following user interactions:

  • press buttons by interpreting the value of num1 (e.g. “100” = button “1” and button “0” and button “0”)
  • click button “+”
  • press buttons by interpreting the value of num2 (e.g. “345” = button “3” and button “4” and button “5”)
  • click button “=”
  • read the value from the result box in the calculator application

Moreover the method checks the displayed result and returns true if the calculation was successful, otherwise false.

public bool Add(decimal num1, decimal num2)
{
    Control button;

    string numStr = num1.ToString(CultureInfo.InvariantCulture);
    foreach (char chars in numStr)
    {
       button = form.FindChildText(chars.ToString());
       Mouse.ClickControl(button);
    }

    button = form.FindChildText("+");
    Mouse.ClickControl(button);

    numStr = num2.ToString(CultureInfo.InvariantCulture);
    foreach (char chars in numStr)
    {
       button = form.FindChildText(chars.ToString());
       Mouse.ClickControl(button);
    }

    button = form.FindChildText("=");
    Mouse.ClickControl(button);

    Control resultBox = form.FindControlId(403);
    decimal result = num1 + num2;
    return resultBox.Text.StartsWith(result.ToString());
}

Properties

The following DigitGrouping property reads or sets the checkbox value from the menu item “Digit grouping”. This is a little bit tricky because the menu item may be at different positions depending on whether the “Standard” or “Scientific” calculator interface is selected. The isDigitGroupingEnabled() method runs through the submenu items of the 2nd menu and returns true if the checkbox is checked, otherwise false.

public bool DigitGrouping
{
    get
    {
        return isDigitGroupingEnabled();
    }
    set
    {
        if (value != isDigitGroupingEnabled())
        {
            menu.SelectItemText("View", "D&igit grouping");
        }
    }
}

private bool isDigitGroupingEnabled() { for(int i=0; i<=menu.GetItemCount(2); i++) { if (menu.GetItemText(2,i) == "D&igit grouping") { return menu.GetItemState(2,i) == MenuState.Checked; } } return false; }

Writing a GUI Test Script

A test script based on the CalcGUITester environment is clear and simple to maintain. First open a new Console Application, import the CalcGUITesterClass and add a reference to the Ranorex framework in order to set up mouse speed, etc. :

using CalcGUITester;
using Ranorex;

The following test case verifies an addition calculation performed by the Calculator using the Add() method. If the calculation was not successful, the method returns false. In this case we abort the application with a return value of 1. We use a return code of 0 if the test completed successfully. In this example we use exception handling to handle errors relating to the user interface interaction. If Ranorex can’t find a control, it throws an exception containing a detailed description about the problem.

[STAThread]
static int Main(string[] args)
{
    try
    {
        Application.SleepTime = 20;
        Mouse.MoveTime = 50;
        Application.ErrorAsException = true;

        CalcGUITesterClass calcTester = new CalcGUITesterClass();

        //Testing add calculation with numeric value
        if (!calcTester.Add(123, 44))
            return 1;
        Console.WriteLine("Adding 123 + 44 is working!");

        //Testing add calculation with decimal value
        if (!calcTester.Add(42.042m, 7.3456m))
            return 1;
        Console.WriteLine("Adding of 42,042 + 7,3456 is working!");

        //Testing digit grouping functionality
        Console.WriteLine("Is digit grouping enabled? " + calcTester.DigitGrouping);

        calcTester.DigitGrouping = true;
        if (!calcTester.DigitGrouping)
            return 1;
        Console.WriteLine("Digit grouping is enabled!");

        return 0;
    }
    catch (RanorexException e)
    {
        Console.WriteLine("EXCEPTIONnSource={0}nSender={1}nMessage={2}nStackTrace={3}n", e.Source, e.Control, e.Message, e.StackTrace);
        Console.WriteLine("TEST FAILED");
        return 1;
    }
}

Conclusion

Writing a GUI Test Automation Framework can be very effective for testing the base features of an application. This test cases can be started after a daily build and give an early notification about the main problems that occurred.

You might also like these articles