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.

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.

C#

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.</remarks>
        void ITestModule.Run()
        {
            Mouse.DefaultMoveTime = 300;
            Keyboard.DefaultKeyPressTime = 100;
            Delay.SpeedFactor = 1.0;
        }
    }
}

VB.NET

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.</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:

C#

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();
    }
}

VB.NET

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.

C#

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

VB.NET

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

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.

Screenshot captured in repository
Screen shot captured in repository

C#

// 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);

VB.NET

' 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

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>'.

C#

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

VB.NET

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.

C#

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;	
	 }
}

VB.NET

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
</testvariable("d0a54427-68ff-4b9d-b861-4882bcec846b")></testvariable("ef09bc93-3447-4ac2-9deb-fe3d78ed5538")>
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