One of Ranorex’s greatest strengths is that non-coders can build rich test suites using very little code. This lowers the learning curve significantly and helps testers be productive regardless of their coding background.
But little code does not mean no code at all. Most test suites need at least a little bit of code. These are probably the most common uses for code in most test suites:
- Random values
- Synthetic test data
- String manipulation
- Date/time manipulation
- Math
There are many other uses for code, such as consuming external libraries or writing low-level UI automation logic, but those uses tend to be far rarer and more complex and rely on a decent coding background. In contrast, the short list above is really far more common and requires only rudimentary coding skills.
This how-to shows how to generate random values and pass them around so they can be used in multiple modules.
It’ll be easier to learn if you follow along, but if you want to jump to the finished product, you can browse or download the Ranorex solution on GitHub:
https://github.com/noamkfir/ranorex-random-values-example
Step 1. Setup
Let’s create a very simple random number generator. You can use the very same techniques with different code to generate other types of values, such as random names and GUIDs, but we’re going to focus on the skeleton here.
We’re going to be using a new solution here, but feel free to do the same exercise in your own existing solution.
- Start by creating a new solution (or opening your existing solution).
- Delete the Recording1.rxrec file in the Projects pane and remove it from the default TestCase test case.
- Next, create a new folder named Modules.
Step 2. Create a random number generator
For non-coders, this is going to be the most difficult part. Having said that, it really isn’t that difficult. Once you understand the basics, you’ll be able to create random generators for other types of values as well, perhaps with a little help from a friendly coder near you.
- Create a new Code Module named GenerateRandomNumber in the Modules folder. If you’re not sure how to do that, simply right-click the Modules folder, select Add > New Item, and then choose the Code Module template in the Ranorex templates category. Type GenerateRandomNumber in the File Name field.
- The next step is to create a Module Variable named Output that can be used for data binding. Find the RandomNumberGenerator class declaration. It should look something like this:
public class GenerateRandomNumber : ITestModule
Right-click the class name or anywhere after the declaration and click Insert New Module Variable. Name the variable Output and leave the default value empty.
This should generate a property named Output with a TestVariable attribute:
string _Output = ""; [TestVariable("9945BD00-61F9-4DBF-A281-E7504E64D01F")] public string Output { get { return _Output; } set { _Output = value; } }
That TestVariable attribute is the glue that makes data binding possible, which is why we use the context menu to create the property instead of adding it manually.
-
Now we’re ready to write the random number generation code. But first, we have to clean things up a bit. Find the Run method.
void ITestModule.Run() { Mouse.DefaultMoveTime = 300; Keyboard.DefaultKeyPressTime = 100; Delay.SpeedFactor = 1.0; }
Delete those three lines. This code module will not be running any UI automation logic, so we don’t need the mouse, keyboard and speed factor settings.
-
Use the Random class to generate a random number and store it in the Output property. Here’s the updated Run method.
void ITestModule.Run() { var random = new Random(); var value = random.Next(); Output = value.ToString(); }
The only real gotcha here is that module variables are always strings, so we have to convert the number returned by
random.Next()
to a string by calling theToString()
method.That’s it. That’s our random number generator. All we had to do was create a Code Module, add a Module Variable and write three lines of code. Save the file and close it. Everything else after this step is much easier.
- Add the GenerateRandomNumber module to the TestCase test case in the test suite. There are lots of ways to do this, but the easiest is probably to just drag it from the Projects pane.
Step 3. Launch the app
This step isn’t strictly related to our challenge, but we want visual proof that what we’re doing actually works. So we’re going to write the random value to Notepad. In this step, we’re just going to launch notepad.
- Create a new Recording Module named LaunchNotepad: right-click the Modules folder, select Add > New Item, choose the Recording Module template and name the file LaunchNotepad.
- In the new module, click Add New Action and then Run Application. In the File Name field, type
notepad
. - You can verify that the recording works by clicking Play and looking for the Notepad app on the task bar.
- Save and close the module and then add the LaunchNotepad module to the TestCase test case in the test suite. Make sure it’s the last module in the test case.
Step 4. Use the random value
The sequence we’ve built so far generates a random value and launches the app. The next step is to create a module that actually uses the random value. In our scenario, we’re simply going to write the random value in Notepad.
Our new module will actually be able to accept any value because we’re going to add to it a Module Variable and pass the random value to it. The module doesn’t know or care that the value it’s using is the random value we generated earlier.
- First of all, create a new Recording Module named UseRandomValue in the Modules folder.
- Add a Module Variable named Input using the Variables dialog. Do not specify a default value.
- Click Add New Action and then Key Sequence. In the Sequence field, open the dropdown and select the
$Input
variable. - Save and close the module and then add the UseRandomValue module to the TestCase test case in the test suite. Make sure it’s the last module in the test case.
Step 5. Bind the random value
We now have a module that generates a random value and a module that can accept any value. All we have to do is connect the dots.
- Open the test suite (the file with the .rxtst extension) if it isn’t already open. Notice that the GenerateRandomNumber and UseRandomValue modules both show Unbound variable: 1 in the Data Binding column.
- Right-click the TestCase test case in the test suite and select Data Binding.
- In the Parameters table (the one on the bottom), add a parameter. The name can be anything, but we’ll call it RandomValue for clarity (it’ll show up on the reports). Leave the Value field empty.
- Finally, click the dropdown in the Module Variable field. You should see both the Output and Input variables in the dropdown. Select them both and click OK. Note that the modules now show Bound variable: 1 in the Data Binding column.
Data binding is a two-way process. The GenerateRandomNumber module assigns the random number to the Output module variable. That assignment propagates to the RandomValue parameter and any other module variable bound to the parameter, including the Input module variable of the UseRandomValue module.
Step 6. Run and verify
We’re done. We’ve created the necessary modules and bound the random value.
To verify that it works, simply run the test suite.
- After it runs, you can switch back to Notepad and see the random value.
- And back in Ranorex, click Expand Details on the report to see the generated value propagate to the UseRandomValue‘s Input module variable.
Nested Test Cases
Test cases can be and are often nested. Two-way binding works at any nesting level. The trick is to remember to define the parameter at the highest-level test case that is shared by all the modules with bound variables. For example, the bindings will work just fine with the following structure:
MyTestSuite - Test Suite (the test suite node)
RootTestCase (define the "global" RandomValue parameter here)
InitializationTestCase (parameters defined here are purely local)
GenerateRandomValue ("Output" variable is bound to the global parameter)
Phase1TestCase
FillPhase1Field ("Input" variable is bound to the global parameter)
Phase2TestCase
FillPhase2Field ("Input" variable is bound to the global parameter)
Generating Other Types of Random Values
You can generate lots of different types of random values, including names, dates and times, unique identifiers, usernames, passwords and many more. Whenever you need to create a different type of random value, just create a new Code Module and replace those three lines of code in Step #2. Everything else stays the same.
Most random value generators rely on:
- the
Random
class, which generates different types of pseudorandom numbers - manipulating
DateTime
values, which aren’t strictly random but simulate randomness pretty well for most UI automation purposes and also have the advantage of being sequential (which helps when debugging test runs) Guid
values
You can use other mechanisms as well, but don’t forget that you always have to convert your random values to strings before assigning them to the Output module variables, regardless of the mechanism you use to generate them.
Robustness
The example we built is very simple. It’s not uncommon for random value generators to define additional input module variables to help specify the rules for the random value generation.
For example, you might want different test cases to be able to specify min and max values for a random number generator, or the number of characters in a random string generator (e.g., for usernames).
Avoid creating unnecessary random value generators. If you already have a random number generator, for example, it is always better to make it more robust than to copy it and change the duplicate.
Summary
Generating random values and using them effectively is a very common requirement. If you can isolate the random value generation in code modules, you’ll be able to create richer test suites that are easier to maintain with less code. If you build multiple test suites, you can even move all your random value generators into a separate module library that you can reuse in all of your solutions.