Ranorex Help Center

How can we help you?

Lesson 7 - Code Modules

Though a Ranorex Recording with only smart actions, variables and user code capabilities is good enough to create robust test automation modules, it might be useful or preferable to write pure Ranorex automation code. In the following section you learn how to create a new code module which automates the process of adding a new credential data set to the KeePass application.



Screencast: In addition to going through the explanations below, you can have a look at the screencast "Code Modules - Benefits and Use Cases" which provides a good overview of reasons for switching to the code level and how do this well. The screencast can be found here: http://youtu.be/4k-lcNxQd2U

Creating Code Modules

Create a new code module by clicking the 'Add Code Module' button at the toolbar.

Adding a new code module with the toolbar button

Adding a new code module with the toolbar button

Alternatively you are able to add a new code module by using the context menu in the Test Suite.

Adding a new code module using the context menu

Adding a new code module using the context menu



Specifying the name used for the code module

Specifying the name used for the code module



After clicking the 'Create' button a new file is added to the project and automatically opened in the file view. Ranorex Studio creates a new test module class which contains a 'Run' method that is ready to be extended with test automation code.


namespace KeePass  
{  
    /// <summary>  
    /// Description of AddCredentialEntry.  
    /// </summary>  
    [TestModule("03F5603B-0DDC-49AA-8C26-4D8088260C66", ModuleType.UserCode, 1)]  
    public class AddCredentialEntry : ITestModule  
    {  
        /// <summary>  
        /// Constructs a new instance.  
        /// </summary>  
        public AddCredentialEntry()  
        {  
            // Do not delete - a parameterless constructor is required!  
        }  
  
        /// <summary>  
        /// Performs the playback of actions in this module.  
        /// </summary>  
        /// <remarks>You should not call this method directly, instead pass the module  
        /// instance to the <see cref="TestModuleRunner.Run(ITestModule)"> method  
        /// that will in turn invoke this method.</see></remarks>  
        void ITestModule.Run()  
        {  
            Mouse.DefaultMoveTime = 300;  
            Keyboard.DefaultKeyPressTime = 100;  
            Delay.SpeedFactor = 1.0;  
        }  
    }  
}  
Namespace KeePass  
    ''' <summary>  
    ''' Description of AddCredentialEntry.  
    ''' </summary>  
    <testmodule("03f5603b-0ddc-49aa-8c26-4d8088260c66", moduletype.usercode,="" 1)=""> _  
    Public Class AddCredentialEntry  
        Implements ITestModule  
        ''' <summary>  
        ''' Constructs a new instance.  
        ''' </summary>  
                ' Do not delete - a parameterless constructor is required!  
        Public Sub New()  
        End Sub  
  
        ''' <summary>  
        ''' Performs the playback of actions in this module.  
        ''' </summary>  
        ''' <remarks>You should not call this method directly, instead pass the module  
        ''' instance to the <see cref="TestModuleRunner.Run(ITestModule)"> method  
        ''' that will in turn invoke this method.</see></remarks>  
        Private Sub ITestModule_Run() Implements ITestModule.Run  
            Mouse.DefaultMoveTime = 300  
            Keyboard.DefaultKeyPressTime = 100  
            Delay.SpeedFactor = 1.0  
        End Sub  
    End Class  
End Namespace


Using Repository within Code Module

In the same way you use a repository in the recording to identify UI elements for automation, you can also use it in code. Simply add a new private member which represents the repository to your code module class as shown below:

    public class AddCredentialEntry : ITestModule  
    {  
        // Repository object to access UI Elements  
        MyFirstTestProjectRepository MyRepo = MyFirstTestProjectRepository.Instance;  
          
        /// Constructs a new instance.  
        public AddCredentialEntry()  
        {  
            // Do not delete - a parameterless constructor is required!  
        }  
          
        void ITestModule.Run()  
        {  
            Mouse.DefaultMoveTime = 300;  
            Keyboard.DefaultKeyPressTime = 100;  
            Delay.SpeedFactor = 1.0;  
              
            // Click 'Add Entry' Button MainMenu  
            MyRepo.MainForm.Edit.Click();  
            MyRepo.KeePass.AddEntry.Click();  
              
            // Set text fields  
            MyRepo.AddEntry.TabSheetAddEntry.Title.TextValue = "WordPressDemo";  
            MyRepo.AddEntry.TabSheetAddEntry.UserName.TextValue = "admin";  
            MyRepo.AddEntry.TabSheetAddEntry.Password.TextValue = "demo123";  
            MyRepo.AddEntry.TabSheetAddEntry.Repeat.TextValue = "demo123";  
            MyRepo.AddEntry.TabSheetAddEntry.URL.TextValue = "bitly.com/wp_demo";  
              
            // Choose an icon  
            MyRepo.AddEntry.TabSheetAddEntry.MBtnIcon.Click();  
            MyRepo.IconPicker.LI_Icon.Click(Location.CenterLeft);  
            MyRepo.IconPicker.ButtonClose.Click();  
              
            // Set Expires  
            MyRepo.AddEntry.TabSheetAddEntry.MBtnStandardExpires.Click();  
            MyRepo.KeePass.MI_Expires.Click();  
              
            // Save Credential Entry  
            MyRepo.AddEntry.ButtonOK.Click();  
        }  
    }  
Public Class AddCredentialEntry  
    Implements ITestModule  
  
    ' Repository object to access UI Elements  
    Private MyRepo As MyFirstTestProjectRepository = MyFirstTestProjectRepository.Instance  
  
    ''' Constructs a new instance.  
            ' Do not delete - a parameterless constructor is required!  
    Public Sub New()  
    End Sub  
  
    Private Sub ITestModule_Run() Implements ITestModule.Run  
        Mouse.DefaultMoveTime = 300  
        Keyboard.DefaultKeyPressTime = 100  
        Delay.SpeedFactor = 1.0  
  
        ' Click 'Add Entry' Button MainMenu  
        MyRepo.MainForm.Edit.Click()  
        MyRepo.KeePass.AddEntry.Click()  
  
        ' Set text fields  
        MyRepo.AddEntry.TabSheetAddEntry.Title.TextValue = "WordPressDemo"  
        MyRepo.AddEntry.TabSheetAddEntry.UserName.TextValue = "admin"  
        MyRepo.AddEntry.TabSheetAddEntry.Password.TextValue = "demo123"  
        MyRepo.AddEntry.TabSheetAddEntry.Repeat.TextValue = "demo123"  
        MyRepo.AddEntry.TabSheetAddEntry.URL.TextValue = "bitly.com/wp_demo"  
  
        ' Choose an icon  
        MyRepo.AddEntry.TabSheetAddEntry.MBtnIcon.Click()  
        MyRepo.IconPicker.LI_Icon.Click(Location.CenterLeft)  
        MyRepo.IconPicker.ButtonClose.Click()  
  
        ' Set Expires  
        MyRepo.AddEntry.TabSheetAddEntry.MBtnStandardExpires.Click()  
        MyRepo.KeePass.MI_Expires.Click()  
  
        ' Save Credential Entry  
        MyRepo.AddEntry.ButtonOK.Click()  
    End Sub  
End Class  



Note By default the class name of a repository is the same as the repository file name (*.rxrep) shown in the project's view.


Now the class uses a private member to refer to the repository in order to reuse some of the objects ('Title', 'Username', 'Password', 'PasswordRepeat' and 'URL') within the 'Run' method.

Repository used within code example

Repository used within code example



Depending on the structure of your repository, accessing items in code might become more and more complex. To reduce complexity - especially when UI elements are used more than once - you should use local variables instead of coding the whole structure of your repository everytime you need to automate a UI element.

var ButtonOK = MyRepo.FormAdd_Entry.ButtonOK;  
ButtonOK.Click();  



Dim ButtonOK = MyRepo.FormAdd_Entry.ButtonOK  
ButtonOK.Click()  





To create local variables as shown in the code above, simply drag and drop elements from the repository browser directly into the code.

Note If the repository itself is not already part of the class(e.g. newly created code modules), a local variable for the repository is generated too.



Accessing Screen Shots within Code Modules

Starting with Ranorex 3.3 it's possible to access screen shots directly in code using the Info object of a repository item. This can be useful if you are going to compare a captured screen shot with the actual appearance of your application under test, for example.

Note Screenshots will be captured automatically if you chose to record image based. Get more information here: Image Based Automation.



Screen shot captured in repository

Screen shot captured in repository

// get the screenshot from the repository  
Bitmap MyScreenshot = MyRepo.IconPicker.LI_IconInfo.GetScreenshot_Icon();  
// create FindOptions with similarity set to 95%  
Imaging.FindOptions MyFindOptions = new Imaging.FindOptions(0.95);  
// compare the captured screenshot with the actual list item  
Validate.CompareImage(MyRepo.IconPicker.LI_Icon, MyScreenshot, MyFindOptions);  



' get the screenshot from the repository  
Dim MyScreenshot As Bitmap = MyRepo.IconPicker.LI_IconInfo.GetScreenshot_Icon()  
' create FindOptions with similarity set to 95%  
Dim MyFindOptions As New Imaging.FindOptions(0.95)  
' compare the captured screenshot with the actual list item  
Validate.CompareImage(MyRepo.IconPicker.LI_Icon, MyScreenshot, MyFindOptions)  




Note Using the FindOptions, you can set custom values like 'similarity'. This option allows you to define the minimum similarity that the image region to search for needs to have in common with the screenshot in order to be considered a match. For further details have a look at Lesson 5: Ranorex Recorder - Image-Based Automation.

Using Variables with Code Modules

In order to use values provided by a data connector within your code modules, you need to add variables to the code. Use the context menu item 'Insert Module Variable'.

Add a new variable to your code module

Add a new variable to your code module



Specify the variable name and the default value

Specify the variable name and the default value



By adding a new variable Ranorex Studio inserts a new code fragment at the current cursor position. A variable implementation consists of a public property '<variablename>' and a private member '_<variablename>'.</variablename></variablename>

string _varTitle = "Wordpress Credentials";  
[TestVariable("9348A7E6-80B6-4A2B-9CBF-0276A236AA3E")]  
public string varTitle  
{  
    get { return _varTitle; }  
    set { _varTitle = value; }  
}  



Private _varTitle As String = "Wordpress Credentials"  
<testvariable("9348a7e6-80b6-4a2b-9cbf-0276a236aa3e")> _  
Public Property varTitle() As String  
    Get  
        Return _varTitle  
    End Get  
    Set  
        _varTitle = value  
    End Set  
End Property 






Now create additional variables for the 'Username', 'Password' and 'URL'. All the module variables will appear immediately in the module browser.

Module variables are shown in the module browser

Module variables are shown in the module browser



Accessing Repository Variables with the Use of Setter Methods

To bind repository variables to external data when accessing the repository element via the code module, you have to create a new module variable to act as a bridge. You can use the setter method for the public variable to also set the repository variable.

Variables used by the repository (e.g. 'varExpires' for the Menu Item in the context menu of KeePass's 'Add Entry Dialog') are easily accessible via the repository, even from code. In order to bind these variables to external data (e.g. one row in our Excel file) in a code module you have to create a new module variable to act as a bridge between external data and repository variables. Following such an approach, it is obviously best to use the setter methods for public variables. A public variable's setter method is called every time the value of this variable is set; i.e. assigning the value to the private variable holding the information for the public property. This method can easily be extended in order to set the repository variable as well.

First two new module variables, 'varExpires' and 'varIconIndex', have to be created the same way as was shown for 'varTitle', 'varPassword'. After that, a simple code line has to be inserted into the setter method for each variable. This code line is used for assigning the passed value to the repository variable and facilitates binding to external data.

string _varRepoIconIndex = "1";  
[TestVariable("EF09BC93-3447-4AC2-9DEB-FE3D78ED5538")]  
public string varRepoIconIndex  
{  
    get { return _varRepoIconIndex; }  
    set {   
        _varRepoIconIndex = value;  
        // Additionally set the Repository Variable in Setter-Method  
        MyRepo.varIconIndex = _varRepoIconIndex;  
 }  
}  
  
string _varRepoExpires = "1 Year";  
[TestVariable("D0A54427-68FF-4B9D-B861-4882BCEC846B")]  
public string varRepoExpires  
{  
    get { return _varRepoExpires; }  
    set {   
        _varRepoExpires = value;  
        // Additionally set the Repository Variable in Setter-Method  
        MyRepo.varExpires = _varRepoExpires;      
     }  
}  



Private _varRepoIconIndex As String = "1"  
<testvariable("ef09bc93-3447-4ac2-9deb-fe3d78ed5538")> _  
Public Property varRepoIconIndex() As String  
    Get  
        Return _varRepoIconIndex  
    End Get  
    Set  
        _varRepoIconIndex = value  
        ' Additionally set the Repository Variable in Setter-Method       
        MyRepo.varIconIndex = _varRepoIconIndex  
    End Set  
End Property  
  
Private _varRepoExpires As String = "1 Year"  
<testvariable("d0a54427-68ff-4b9d-b861-4882bcec846b")> _  
Public Property varRepoExpires() As String  
    Get  
        Return _varRepoExpires  
    End Get  
    Set  
        _varRepoExpires = value  
        ' Additionally set the Repository Variable in Setter-Method               
        MyRepo.varExpires = _varRepoExpires  
    End Set  
End Property  






Thus the two columns in the Excel file can be bound to these module variables. This binding causes the variables to be set for each iteration in the test case. When setting those variables, the extended functionality also sets the repository variable assuring that the correct icon will be used and clicked in our example.

Using Code Modules within Test Cases

The code module implemented above is now ready to be run by a test case. Add a new test case ('TC_AddEntryFromCode') to your test suite and reuse already existing modules to start KeePass, login at the beginning and to validate, delete, save and close it at the end of the test case. You can use drag and drop to quickly insert the newly created code module into the test case.

Drag and drop the code module into a test case and combine it with recordings

Drag and drop the code module into a test case and combine it with recordings



Now you can reuse the existing data connector created during Lesson 3: Data-Driven Testing with your new test case.
Reuse the existing data connector by choosing the item from the drop-down

Reuse the existing data connector by choosing the item from the drop-down

Bind the newly created variables to the data connector's columns, i.e. columns from the Excel file

Bind the newly created variables to the data connector's columns, i.e. columns from the Excel file