ServiceNowのテストフレームワークを使い倒す

# 概要

ServiceNowのAutomated Test FrameworkでRun Server Side Scriptのテストを作成すると、作成したテスト設定のTest Script欄にコメントで詳細なテスト方法が記述されている、その内容を読み解きながら実際に試してみる。

# 本題
## Jasmineとの住み分け

```javascript

// You can use this step to execute a variety of server-side javascript tests including
// jasmine tests and custom assertions
```

jasmineとServiceNowの独自のテストフレームワークの２種類を使用する事が出来る。
ServiceNowのテスト機能を最大限に活用するには、ServiceNow のテスト機能を使うのが良いだろう。

## 戻り値について

```javascript
// Pass or fail a step: Override the step outcome to pass or fail. This is ignored 
//                      by jasmine tests
//
//  - Return true from the main function body to pass the step
//  - Return false from the main function body to fail the step
```

戻り値として、trueを返すとテスト成功(pass)
戻り値として、falseを返すとテスト失敗(fail)
と判断される。

なお、この戻り値によるテストはjasmineテストの場合は、無視される。

## 戻り値を試してみる

### trueを返す
```javascript
(function(outputs, steps, stepResult, assertEqual) {
    // add test script here
	return true;

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

![return true.png](https://qiita-image-store.s3.amazonaws.com/0/197947/f7b0d7be-dff0-c403-3c2a-62a79f713a9b.png)

### falseを返す

```javascript
(function(outputs, steps, stepResult, assertEqual) {
    // add test script here
	return false;

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

![return false.png](https://qiita-image-store.s3.amazonaws.com/0/197947/419796c0-a193-b5b9-9f4f-4ebe1d44f77e.png)


## outputsを使ってテストステップ間でデータの受け渡しを行う

```javascript

// outputs:       Pre-defined Step config Output variables to set on this step during 
//                execution that are available to later steps
//
// steps(SYS_ID): A function to retrieve Output variable data from a step that executed
//                earlier in the test. The desired step's sys_id is required
```

outputsオブジェクトに値を設定することにより、以降のテストステップに値を受け渡すことが可能。
以降のテストステップでは、steps関数により前のテストのoutputsオブジェクトを取得することが可能。

## outputsを試してみる

１つ目のテストステップ

```javascript
(function(outputs, steps, stepResult, assertEqual) {
	var salesRecord = new GlideRecord('x_211750_angular_a_sales');
	salesRecord.setValue('customername','test user');
	salesRecord.setValue('unitprice', 200);
	salesRecord.setValue('quantity',4);
	
	outputs.record_id = salesRecord.insert(); 
	
})(outputs, steps, stepResult, assertEqual);
```

なお、２つ目のテストステップのこのテストステップのsys_idが必要となるので、
Test Stepのメニューの「Copy sys_id」でsys_idをクリップボードにコピーしておく。

![copy_sys_id.png](https://qiita-image-store.s3.amazonaws.com/0/197947/34558d27-433b-cd79-8e6e-9a7218d0ce9d.png)


２つ目のテストステップ

```javascript
(function(outputs, steps, stepResult, assertEqual) {
	
    var previoudObject = steps('57ad9350dbe11b0004f171efbf96190d');
	gs.info('previoudObject.record_id = ' + previoudObject.record_id);
	var salesRecord = new GlideRecord('x_211750_angular_a_sales');
	
	salesRecord.get(previoudObject.record_id);

	var assertion = {
		name: "レコードがありました", 
		shouldbe: 'test user', 
		value: salesRecord.customername};

	assertEqual(assertion);

	return true;

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

steps関数について説明する。

```javascript
var previoudObject = steps('57ad9350dbe11b0004f171efbf96190d');
```
steps関数により前のステップのoutputsオブジェクトを取得が可能だ。
steps関数の引数は、outputsオブジェクトを取得したいテストステップのsys idだ。
テストステップのsys_idは１つめのテストステップを作成時にクリックボードにコピーしたものだ。
テストの中で既に実行済みの任意のテストステップのoutputsを取得できる。

実行結果は次の通り

![outputtestresult.png](https://qiita-image-store.s3.amazonaws.com/0/197947/3be611c2-97e9-01bc-75ca-474b000fbd28.png)

## stepResult.setOutputMessageでテスト結果を明示的に出力する

```javascript
// stepResult.setOutputMessage: Log a message to step results after step executes.
//                              Can only be called once or will overwrite previous 
//                              message
//
```

Test Resultにテストの検証結果をテストステップごとに出力が可能。
なお、１つのテストステップでメッセージは１回のみ設定可能で、後勝ちになる。

## stepResult.setOutputMessageを使ってみる

```javascript
(function(outputs, steps, stepResult, assertEqual) {
	stepResult.setOutputMessage('レコードの検証に成功しました。');

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

実行結果は次の通り

![messageresult.png](https://qiita-image-store.s3.amazonaws.com/0/197947/df81a4fe-de40-604e-c272-fbb25b594abc.png)


## describeやitについて

```javascript
// Note: describe is only supported in Global scope.
// Use 'describe' to create a suite of test scripts and 'it' to define test expectations
```

describeやitというのはjasmineテストフレームワークで使用するもので、
itでテストケースの定義、describeでテストスイートの定義を行うが、
ServiceNowを使用する場合は、ServiceNowのTest Suite機能を利用するので、jasmineのdescribeやitは通常は利用しないだろう。

使用する場合はGlobalスコープでのみ使用可能。

```javascript
// make sure to uncomment jasmine.getEnv().execute(); outside the function body
```

また、jasmineのテストフレームワークを利用するには、下記の行のコメントアウトを解除して有効にしておく必要がある。

```javascript

jasmine.getEnv().execute();
```


## assertEqualで検証

```javascript
// assertEqual: A function used to compare that assertion.shouldbe == assertion.value;
//              in case of failure it throws an Error and logs that the assertion by
//              name has failed
```

こちらは既に試しているが、値を検証するのに使用する。
次のようなオブジェクトを引数に指定して実行する。

```javascript
   var assertion = {
        name: "レコードがありました", 
        shouldbe: 'test user', 
        value: salesRecord.customername};

   assertEqual(assertion);
```

outputsの２つ目のステップのコードで利用しているので、そちらで確認して欲しい。
なお、オブジェクトのプロパティは次の通り

|名称 | 説明 |
|---|---|
|name|検証の説明を書く|
| shouldbe|期待する値|
|value|実際の値|