mcpField
A
atf-testing

atf-testing

github.com/serac-labsテスト・品質7759 回インストール9 週間前に更新
リポジトリ

atf-testing について

ServiceNow の Automated Test Framework(ATF)テストとテストスイートを作成・実行するスキルです。UI とサーバーサイドのステップ、アサーション、パラメーター化、データの後片付けを扱い、回帰テストや継続的インテグレーションに役立ちます。

主な機能

  1. 01テストとテストスイートの作成
  2. 02UI とサーバーサイドのステップ追加
  3. 03フィールド値と結果の検証
  4. 04テストのパラメーター化
  5. 05テストデータの準備と後片付け

活用シーン

  1. 01インシデントの作成と更新をテスト
  2. 02アプリの回帰テストスイートを実行
  3. 03異なるユーザーロールでの動作を検証

MCP 対応

ATF テスト、ステップ、スイートの作成、テスト実行、結果取得、既存テストの検索に使う MCP ツールを説明します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/serac-labs/serac --skill atf-testing

インストール後、Claude Code で/atf-testingを入力して読み込まれたか確認します。

詳細

ServiceNow 向け自動テストフレームワーク(ATF)

ATF は ServiceNow アプリケーション向けの自動テスト機能を提供し、回帰テストと継続的インテグレーションを可能にします。

ATF のアーキテクチャ

テストの階層
Test Suite: Incident Management Tests
├── Test: Create Incident
│   ├── Step 1: Impersonate User
│   ├── Step 2: Open New Record
│   ├── Step 3: Set Field Values
│   ├── Step 4: Submit Form
│   └── Step 5: Assert Values
├── Test: Assign Incident
│   └── Steps...
└── Test: Resolve Incident
    └── Steps...
主要なテーブル
テーブル用途
sys_atf_testテスト定義
sys_atf_step個々のテストステップ
sys_atf_test_suiteテストスイートのグループ
sys_atf_test_suite_testスイートとテストの関係
sys_atf_test_resultテスト実行結果

テストステップの種類

一般的なステップの種類
ステップの種類用途例
Impersonate特定のユーザーとして実行ITIL ユーザーとしてテスト
Open a New Form新しいレコードを作成新しいインシデントフォーム
Open an Existing Formレコードを編集INC0010001 を開く
Set Field Valuesフィールドに値を入力優先度と説明を設定
Click a UI Actionボタンを実行「Save」をクリック
Assert Field Values値を検証優先度 = 1
Run Server Side Scriptスクリプトを実行カスタム検証
Wait実行を一時停止非同期処理を待機

テストの作成

基本的なテスト構造(ES5)
// Create a new ATF test
var test = new GlideRecord("sys_atf_test")
test.initialize()
test.setValue("name", "Test: Create High Priority Incident")
test.setValue("description", "Verify high priority incident creation workflow")
test.setValue("active", true)
test.setValue("application", "global") // or scoped app sys_id
var testSysId = test.insert()

// Add test steps
function addTestStep(testId, order, stepType, config) {
  var step = new GlideRecord("sys_atf_step")
  step.initialize()
  step.setValue("test", testId)
  step.setValue("order", order)
  step.setValue("step_config", stepType)

  // Set step-specific configuration
  for (var key in config) {
    if (config.hasOwnProperty(key)) {
      step.setValue(key, config[key])
    }
  }

  return step.insert()
}
Impersonate ステップ
// Step 1: Impersonate ITIL user
addTestStep(testSysId, 100, "sys_atf_step_config_impersonate", {
  description: "Impersonate ITIL user",
  inputs: JSON.stringify({
    user: "itil", // or sys_id
  }),
})
Open New Form ステップ
// Step 2: Open new incident form
addTestStep(testSysId, 200, "sys_atf_step_config_open_new_form", {
  description: "Open new incident form",
  inputs: JSON.stringify({
    table: "incident",
  }),
})
Set Field Values ステップ
// Step 3: Set field values
addTestStep(testSysId, 300, "sys_atf_step_config_set_field_values", {
  description: "Set incident fields",
  inputs: JSON.stringify({
    table: "incident",
    values: [
      { field: "short_description", value: "ATF Test Incident" },
      { field: "priority", value: "1" },
      { field: "category", value: "network" },
      { field: "caller_id", value: "admin" },
    ],
  }),
})
Submit Form ステップ
// Step 4: Submit form (click Save)
addTestStep(testSysId, 400, "sys_atf_step_config_click_ui_action", {
  description: "Save the incident",
  inputs: JSON.stringify({
    ui_action: "sysverb_insert", // Submit/Insert action
  }),
})
Assert Field Values ステップ
// Step 5: Assert values
addTestStep(testSysId, 500, "sys_atf_step_config_assert_field_values", {
  description: "Verify incident was created correctly",
  inputs: JSON.stringify({
    table: "incident",
    assertions: [
      {
        field: "priority",
        operator: "equals",
        value: "1",
      },
      {
        field: "state",
        operator: "equals",
        value: "1", // New
      },
      {
        field: "number",
        operator: "is not empty",
      },
    ],
  }),
})

サーバーサイドスクリプトのステップ

カスタム検証スクリプト(ES5)
// Step: Run Server Side Script
// Script (ES5 only!):

;(function (outputs, steps, params, stepResult) {
  // Access outputs from previous steps
  var incidentSysId = steps["step_sys_id"].record_id

  // Perform custom validation
  var gr = new GlideRecord("incident")
  if (gr.get(incidentSysId)) {
    // Check business rule fired
    if (gr.getValue("assignment_group") === "") {
      stepResult.setOutputMessage("Assignment group not set by business rule")
      stepResult.setFailed()
      return
    }

    // Check SLA attached
    var sla = new GlideRecord("task_sla")
    sla.addQuery("task", incidentSysId)
    sla.query()

    if (!sla.hasNext()) {
      stepResult.setOutputMessage("No SLA attached to incident")
      stepResult.setFailed()
      return
    }

    // All validations passed
    outputs.incident_number = gr.getValue("number")
    outputs.sla_count = sla.getRowCount()
    stepResult.setOutputMessage("All validations passed")
  } else {
    stepResult.setOutputMessage("Incident not found")
    stepResult.setFailed()
  }
})(outputs, steps, params, stepResult)
データセットアップスクリプト(ES5)
// Step: Setup test data
;(function (outputs, steps, params, stepResult) {
  // Create test user if needed
  var user = new GlideRecord("sys_user")
  user.addQuery("user_name", "atf_test_user")
  user.query()

  if (!user.next()) {
    user.initialize()
    user.setValue("user_name", "atf_test_user")
    user.setValue("first_name", "ATF")
    user.setValue("last_name", "Test User")
    user.setValue("email", "[email protected]")
    user.setValue("active", true)
    outputs.user_sys_id = user.insert()
  } else {
    outputs.user_sys_id = user.getUniqueValue()
  }

  stepResult.setOutputMessage("Test user ready: " + outputs.user_sys_id)
})(outputs, steps, params, stepResult)
クリーンアップスクリプト(ES5)
// Step: Cleanup test data (always runs)
;(function (outputs, steps, params, stepResult) {
  var testRecordId = steps["create_incident_step"].record_id

  if (testRecordId) {
    var gr = new GlideRecord("incident")
    if (gr.get(testRecordId)) {
      gr.deleteRecord()
      stepResult.setOutputMessage("Cleaned up test incident: " + testRecordId)
    }
  }
})(outputs, steps, params, stepResult)

テストスイート

テストスイートの作成
// Create test suite
var suite = new GlideRecord("sys_atf_test_suite")
suite.initialize()
suite.setValue("name", "Incident Management Regression Suite")
suite.setValue("description", "Full regression tests for incident management")
suite.setValue("active", true)
var suiteSysId = suite.insert()

// Add tests to suite
function addTestToSuite(suiteId, testId, order) {
  var link = new GlideRecord("sys_atf_test_suite_test")
  link.initialize()
  link.setValue("test_suite", suiteId)
  link.setValue("test", testId)
  link.setValue("order", order)
  return link.insert()
}

addTestToSuite(suiteSysId, createTestId, 100)
addTestToSuite(suiteSysId, assignTestId, 200)
addTestToSuite(suiteSysId, resolveTestId, 300)

パラメーター化されたテスト

テストパラメーターの使用
// Test with parameters
var test = new GlideRecord('sys_atf_test');
test.initialize();
test.setValue('name', 'Test: Create Incident with Priority');
test.setValue('parameters', JSON.stringify({
    priority: '2',
    category: 'software'
}));
test.insert();

// In step, reference parameter
{
    "values": [
        { "field": "priority", "value": "${priority}" },
        { "field": "category", "value": "${category}" }
    ]
}

MCP ツールとの連携

利用可能な ATF ツール
ツール用途
snow_create_atf_testテストを作成
snow_create_atf_test_stepテストにステップを追加
snow_create_atf_test_suiteスイートを作成
snow_execute_atf_testテストを実行
snow_get_atf_results結果を取得
snow_discover_atf_tests既存のテストを検索
ワークフローの例
// 1. Create test
var testId = await snow_create_atf_test({
  name: "Test: Incident Priority Escalation",
  description: "Verify priority changes trigger notifications",
})

// 2. Add steps
await snow_create_atf_test_step({
  test_id: testId,
  order: 100,
  type: "impersonate",
  user: "itil",
})

await snow_create_atf_test_step({
  test_id: testId,
  order: 200,
  type: "server_script",
  script: createIncidentScript,
})

// 3. Execute test
var resultId = await snow_execute_atf_test({
  test_id: testId,
})

// 4. Get results
var results = await snow_get_atf_results({
  result_id: resultId,
})

ベストプラクティス

  1. テストデータを分離する - 各テストでテストデータを作成し、クリーンアップします
  2. なりすましを使用する - 実際のユーザーロールとしてテストします
  3. アトミックなテスト - 各テストで 1 つのシナリオを検証します
  4. わかりやすい名前 - テストとステップの説明を明確にします
  5. ステップの順序付け - 挿入しやすいように 100、200、300 を使用します
  6. 非同期処理に対応する - 非同期操作には待機ステップを追加します
  7. 必ずクリーンアップする - クリーンアップには finally ステップを使用します
  8. パラメーター化する - 再利用可能なテストにはパラメーターを使用します

一般的なアサーション

アサーション用途
equals値の完全一致
not equals値の除外
is emptyフィールドが空であること
is not emptyフィールドに値があること
contains部分文字列の一致
starts with接頭辞の一致
greater than数値の比較
less than数値の比較

コメント