ben_knight
Kilo Guru

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:

find_real_file.png

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:

find_real_file.png

 

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:

  1. Find how many records exist for our query.
  2. Generates a random index from 0 - Total records.
  3. Selects the records at the random index.
  4. Adds the table and id to our outputs.
  5. 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

find_real_file.png

 

Step Configuration

find_real_file.png

 

Test Step List View

find_real_file.png

 

Referencing the found record in other steps

find_real_file.png

 

 

 Additions

Some ideas for additions that may prove useful:

  1. 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.
  2. Add the attribute "allow_related_list_query=true" to the conditions input variable. This will allow related list queries to the conditions.
Comments
Rosemary4
Tera Expert

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.

Ramesh2
Tera Guru

Thank you Ben. This helped me.

HarI98
Tera Expert

Works like a charm.

Community Alums
Not applicable

Thank you so much. It really helped.

Version history
Last update:
‎09-06-2020 06:52 PM
Updated by: