ServiceNowのScript IncludeでGlideRecordを使ってレコード一括更新を行う

# 概要

次のようなオブジェクトを引数にとって、Saleテーブルのproductが一致するレコードのunitpriceを一括更新するスクリプトをScript includeで作成し、その単体テストを実施する。

```javascript:引数のデータ型
	var data = {
		unitprice: "500",
		product: "PPP"
	};
```

なお、Tableは下記で作成したSales Tableを使用する。
[ServiceNowでTableを作成する](https://qiita.com/sukkyxp/items/46a06665131b37ce3f2b)

# スクリプト作成手順
## Script Includeを作成する。

Studioを使ってCreate Application FileでServer DevelopmentカテゴリーのScript Includeを選択してCreateをクリックする。
Nameに「updateProductPrice」を入力して「Submit」をクリックする。

![AddServerIncludeScript.png](https://qiita-image-store.s3.amazonaws.com/0/197947/c3292d57-6955-5d74-f4fa-94220863e721.png)


## スクリプトを入力する。

Scriptに下記の通り入力する。

```javascript
var updateProductPrice = Class.create();
updateProductPrice.prototype = {
    initialize: function() {
    },
	update:function(data) {
		gs.info('update product price called!');
		gs.info('data = ' + data);
		var product = data.product;
		var unitprice = data.unitprice;
		
		gs.info('prodcut = ' + product);
		gs.info('price = ' + unitprice);
		
		var grSales = new GlideRecord('x_211750_angular_a_sales');

		grSales.addQuery('product',product);
		grSales.query();
		
		if(grSales.next()){
		  grSales.unitprice = unitprice;
		  grSales.update(); 
		}
	},

    type: 'updateProductPrice'
};
```

## スクリプトの解説


```javascript
		var product = data.product;
		var unitprice = data.unitprice;
```

引数のdataからキー名から値をそれぞれ取得する。

```javascript:GlideRecord
		var grSales = new GlideRecord('x_211750_angular_a_sales');
```

GlideRecordを作成する。引数にはSales TableのNameを指定している。

検索条件を指定してレコードを取得する。

```javascript
		grSales.addQuery('product',product);
		grSales.query();
````

ここでは、product項目　= 引数のproductを検索条件としてレコードを取得している。


```javascript
		if(grSales.next()){
		  grSales.unitprice = unitprice;
		  grSales.update(); 
		}
```

next()で1件目のレコードが取得出来たら、レコードのunitpriceに引数のunitpriceを設定する。update()で、指定したproductのレコードのunitpriceが一括更新できる。

SQLにすると、
update sale set unitprice = unitprice where  product = product;
の実行と同等の処理となる。


# 単体テストで動作を確認する

## テスト作成
テストは、StudioではなくServiceNowのアプリケーションブラウザーのNavigatorのAutomated Test Framework -> Testsを選択して行う。

![AutomatedTestFramework.png](https://qiita-image-store.s3.amazonaws.com/0/197947/af1ea2a7-6c0f-0be8-b211-26bed4033d56.png)


Testsのレコードリストの画面で「New」をクリックし新たにテストを作成する。
Nameに任意のテスト名を入力して一旦Submitをクリックして保存する。

保存すると、Test Stepのレコードリストが表示される。
「Add Test Step」でテストステップを追加していく。

![TestStepsRecord.png](https://qiita-image-store.s3.amazonaws.com/0/197947/9d54d78b-07f2-e606-0262-974d919167fc.png)


## テストレコードの追加するテストステップを追加

「Add Test Step」をクリックし、ServerカテゴリのRecord Insertを選択して「Next」をクリクする。

![AddTestStepServerRecordnsert.png](https://qiita-image-store.s3.amazonaws.com/0/197947/fc550ce8-9941-2104-4a1a-6191a7efeb99.png)

次のようにレコード追加の設定を行う。なお、Desciptionは設定内容から自動生成されるが、UnitPriceの金額がDescription内で誤差が発生している。

![TestRecordInsert.png](https://qiita-image-store.s3.amazonaws.com/0/197947/8e56b339-c92f-73a1-94e8-2cb76e3ac4f0.png)



## テスト対象のスクリプトを起動するテストステップを追加

「Add Test Step」をクリックし、ServerカテゴリのRun Server Side Scriptを選択して「Next」をクリックする。
Test Scriptに次の入力を行う。Test Scriptには使用例などのコメントが大量に記述されているが、一旦全て削除してから入力する。

```javascript

(function(outputs, steps, stepResult, assertEqual) {
    // add test script here
	var requestData = {
		unitprice: "500",
		product: "PPP"
	};
	
	var updateProductPriceObj = new updateProductPrice();		
	updateProductPriceObj.update(requestData);

})(outputs, steps, stepResult, assertEqual);
```

requestDataオブジェクトにunitPriceとproductを設定しupdateProductPrice.updateの引数として渡してScript Includeのスクリプトを実行している。

## テスト結果の確認のためテストステップを追加

「Add Test Step」をクリックし、ServerカテゴリのRun Server Side Scriptを選択して「Next」をクリックする。
Test Scriptに次の入力を行う。

```javascript
(function(outputs, steps, stepResult, assertEqual) {
    // add test script here
	var grSales = new GlideRecord('x_211750_angular_a_sales');

	grSales.addQuery('product','PPP');
	grSales.query();

	if(grSales.next()){
		var unitPrice = grSales.getValue('unitprice');
		
		assertEqual({name: "unitPrice of Product PPP is updated!", shouldbe: 500, value: unitPrice});
		
		stepResult.setOutputMessage("レコードが正常の更新されていることを確認");
		return true;
		
	} else {
		
		stepResult.setOutputMessage("レコードが正常に更新されなかった");
		return false;
	}

})(outputs, steps, stepResult, assertEqual);

```

ここでは、GlideRecodeの説明は省略する。
テストで独自に使用するスクリプトについて解説する。
assertEqualは、name, shouldbe, valueを持つオブジェクトを引数にとり、テスト結果kの検証を行う。nameは検証内容を説明する文言、shouldbeは期待する値で、valueには実際の値を設定する。
shouldbeとvalueが一致しないとテスト失敗と判定される。

stepResult.setOutputMessageによってテスト結果をTest Result画面にログとして出力する。
テストが失敗の場合は、
return false;
を返すことでテスト失敗と判定される。
なおテスト成功の場合は、特にreturn true;を呼ばなくても成功と判定される。

## 最後に

実際の単体テストとしては、条件に不一致のレコードの更新されていないことの確認や、複数の対象レコードがあった場合の確認なども必要となるが、今回は手順の作成のみのため実施していない。