[object Object]

Automated control testing in ServiceNow GRC looks great until an external auditor asks, “How does this test know the control is operating?” If the answer is “it ran a query and got results,” you have evidence theater, not control testing.

What a real automated test looks like

A control test must answer three questions with reproducible artifacts:

  1. What population was tested? — exact query, point-in-time
  2. What was the expected outcome? — written assertion
  3. What was the actual outcome? — sampled records, not just a count

Most homegrown automation answers question 1 and skips 2 and 3.

The control test pattern

Build the test as a scoped Script Include called from a scheduled Continuous Monitoring indicator.

var ChangeApprovalTest = Class.create();
ChangeApprovalTest.prototype = {
  execute: function() {
    var population = new GlideRecord('change_request');
    population.addQuery('state', 'closed');
    population.addQuery('sys_created_on', '>=', gs.daysAgo(30));
    population.addQuery('type', 'normal');
    population.query();
    var pop = population.getRowCount();

    var fail = new GlideRecord('change_request');
    fail.addEncodedQuery('state=closed^sys_created_onRELATIVEGT@dayofweek@ago@30');
    fail.addQuery('type', 'normal');
    fail.addQuery('approval', '!=', 'approved');
    fail.query();
    var failures = [];
    while (fail.next()) failures.push(fail.getUniqueValue());

    return { population: pop, failures: failures };
  },
  type: 'ChangeApprovalTest'
};

The returned failures array is the sample the auditor will pull.

Persist the test result with evidence

Store every test run with the population query, the failure list, and a hash of the platform state. Use the sn_grc_control_test table extended with u_population_query and u_failure_sysids.

Sampling versus full population

For high-volume controls (millions of records per period), full-population testing is impractical. Document the sampling methodology in writing — random with seed, statistical confidence, sample size — and let the script use the same seed each run for reproducibility.

The auditor’s reproducibility test

A good external auditor will ask: “Re-run the test against last quarter’s data.” If your script has no point-in-time semantics, you cannot. Build the date floor as a parameter, not a hardcoded gs.daysAgo(30).

What kills automation

Vague control language. “Changes are appropriately approved” is not testable. Force the control owner to define the test in operational terms before you write any script.

What to do this week

Pick your three most-tested controls. Confirm each has a script-based test that returns sample sys_ids, persists evidence, and is reproducible point-in-time. The first one missing any of these is your next sprint.

[object Object]
Share