- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
on 09-06-2020 06:52 PM
The results of this article can be downloaded in ServiceNow Share.
Purpose
When working with the Automated Test Framework it is often the case that you want to work with existing data from a clone of production by you do not know the exact records that will match what you need. ServiceNow even recommends this as best practice in their Automated Test Framework (ATF) Fundamentals on demand training. Below is a screenshot of that training as of orlando:
My problem with this is they expect you to write a script any time you need to select a randomised record. Instead of this I believe there should be a test step enabling randomised selections and as it doesn't exist out of the box I have made one.
Creating a Custom Server Step
The first thing to do is get an understanding of what inputs and outputs you want from this step. For me I wanted something similar to the existing Record Query, where it requires just a table and conditions to be specified. It then outputs the table and record id. I can then use this ID going forward within other test steps.
Lets create the Test Step Config record to add these inputs and output to. Go to "Automated Test Framework (ATF)" - "Administration" - "Step Configurations" and click New. Here is my configuration:
Submit this and then lets create the input and output variables.
Variables
Lets first create the inputs. As I mentioned before I want two inputs to define the table and the conditions for the query.
Table
- Type: Table Name
- Label: Table
- Column name: u_table
- Mandatory: Checked
The rest of the fields are let to their defaults.
Conditions
- Type: Conditions
- Label: Field Values
- Column name: u_field_values
- Use dependent field: Checked
- Dependent on field: Table - This is the variable we defined first. This allows our conditions field to know what columns exist on the table.
The rest of the fields are let to their defaults.
Next we can create the output variables:
Table
- Type: Table Name
- Label: Table
- Column name: u_table
The rest of the fields are let to their defaults.
Record ID
- Type: Document ID
- Label: Record
- Column name: u_record
The rest of the fields are let to their defaults.
Description Generation
I am borrowing from the out of the box Record Query description script for this as the core description functionality it the same. As it is copied I will not go through how it works.
function generateDescription() {
var td = GlideTableDescriptor.get(step.inputs.u_table);
if (!td) {
gs.log("Invalid table name in test step: " + step.inputs.u_table);
return gs.getMessage("Set field values");
}
var descriptionGenerator = new ATFStepDescriptionGenerator();
var description;
description = gs.getMessage("Validate there is at least one record in '{0}' matching query:\n{1}",
[step.inputs.u_table.getDisplayValue(),
descriptionGenerator.getConditionDescription(step.inputs.u_table, step.inputs.u_field_values)]);
return description;
}
generateDescription();
Script
Now we have our variables we can define our script. As we want our script to be able to select a random record from the whole table we will be finding how many records match our condition first. Then we can find the record we want and assign it to our outputs.
I have put the script below, but a quick summary of what it does is:
- Find how many records exist for our query.
- Generates a random index from 0 - Total records.
- Selects the records at the random index.
- Adds the table and id to our outputs.
- Fails the step if no record is found.
(function executeStep(inputs, outputs, stepResult, timeout) {
// Find how many rows are in the table for this query
var ga = new GlideAggregate(inputs.u_table);
ga.addEncodedQuery(inputs.u_field_values);
ga.addAggregate('COUNT');
ga.query();
if (ga.next()) {
var totalRows = ga.getAggregate('COUNT');
// Get a random row based on the number of rows in a table
var randomRow = Math.floor(Math.random() * totalRows);
var gr = new GlideRecord(inputs.u_table);
gr.addEncodedQuery(inputs.u_field_values);
gr.chooseWindow(randomRow, randomRow + 1);
gr.query();
if (gr.next()) {
outputs.u_table = inputs.u_table;
outputs.u_record = gr.getValue('sys_id');
stepResult.setOutputMessage('Record "' + outputs.u_record + '" found.');
stepResult.setSuccess();
return;
}
}
stepResult.setOutputMessage('No records found for table "' + inputs.u_table + '" and query "' + inputs.u_field_values + '"');
stepResult.setFailed();
}(inputs, outputs, stepResult, timeout));
And that is it. A reusable step that will randomly select a record. It is such a simple thing that I believe this should be provided out of the box. Here is what it looks like when you use it.
Selecting the step
Step Configuration
Test Step List View
Referencing the found record in other steps
Additions
Some ideas for additions that may prove useful:
- Add a key field which will return a value from the field mentioned in this key. It will allow you to get any data from a record, rather than just the sys_id.
- Add the attribute "allow_related_list_query=true" to the conditions input variable. This will allow related list queries to the conditions.
- 4,507 Views

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you! I was really surprised that this feature isn't available out of the box. Being able to test with random records ensures that you're not just happy path testing with data that you know will produce a successful test result.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you Ben. This helped me.
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Works like a charm.

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Thank you so much. It really helped.