KarateによるAPIのシナリオテスト自動化 #06 Assertions-Contains

# はじめに
[前回（#05 Assertions-Matching）](https://qiita.com/takanorig/items/ab69ddd7c1995ebf30be)は、[Karate](https://github.com/intuit/karate) における Assert の仕方について確認しました。
ただ、Assert に関する機能は豊富で、前回だけでは書き切れなかった内容があるため、前回分と今回分の2回に分けて説明したいと思います。

# Assertの仕方

## Contains Matching

通常の`match ==`コマンドは、完全一致ですが、`match contains`コマンドは、テスト対象データの部分一致を確認できます。

```cucumber
Scenario: Contains Matching

* def test = {id: '001', first_name: 'John', last_name: 'Smith', age: 20}

# contains / not contains
* match test contains {id:'001'}
* match test contains {first_name: 'John', last_name: 'Smith'}
* match test !contains {foo: '001'}
* match test contains only {id: '001', first_name: 'John', last_name: 'Smith', age: 20}
* match test contains only {age: 20, first_name: 'John', last_name: 'Smith', id: '001'}

# array
* def testArray = [1, 2, 3]

* match testArray contains 1
* match testArray contains [1, 2]
* match testArray !contains 4
* match testArray !contains [4, 5]
* match testArray contains only [1, 2, 3]

# marker
* def test = {id: '001', name: { first: 'John', last: 'Smith' }, age: 20}
* match test contains {id: '#string', name: '#notnull', age: '#number'}
```

`match contains`コマンドは、JSONデータはもちろん、通常の変数や配列でも利用できますし、Markerとの組み合わせてでも利用できます。
`!contains`（対象を含まない場合）や`contains only`（対象のみを含む場合）などの使い方もあります。

![karate06_contains_matching.png](https://qiita-image-store.s3.amazonaws.com/0/22893/4ab8c220-23b0-1744-63df-5156786aa488.png)


## JSON Path によるチェック

これまで、JSON形式のデータによるチェックは説明してきていますが、JSON形式だけでなく、JSON Pathを使ったチェックも可能です。

```cucumber
Scenario: JSON Path

* def jsonData = 
"""
{
  name: 'Billie',
  kittens: [
    { id: 23, name: 'Bob' },
    { id: 42, name: 'Wild' }
  ]
}
"""

* match jsonData.kittens[*].id == [23, 42]

# 'contains' for JSON arrays
* match jsonData.kittens[*].id contains 23
* match jsonData.kittens[*].id contains [23, 42]

# nested objects within JSON arrays
* match jsonData.kittens contains [{ id: 42, name: 'Wild' }, { id: 23, name: 'Bob' }]
```

この例では、複数要素をまたがるパラメータのチェックや、ネストされたパラメータをチェックしています。
もちろん、 JSON Pathは、`match contains`コマンドだけでなく、通常の`match`コマンドでも利用できます。

![karate06_json-path.png](https://qiita-image-store.s3.amazonaws.com/0/22893/67effea3-d571-cbdb-1444-1df07ed7cb20.png)


## 個別の要素のチェック
`match each`コマンドを利用すると、配列などの複数要素の要素に対して、まとめて個別の要素をチェックすることが可能です。
型や範囲などを、一度にチェックするのに便利なコマンドです。

```cucumber
Scenario: Validate every element

* def arrayData = {foo: [{bar: 1, baz: 'a'}, {bar: 2, baz: 'b'}, {bar: 3, baz: 'c'}]}

# validate each element
* match each arrayData.foo == {bar: '#number', baz: '#string'}

# 'contains' with 'each'
* match each arrayData.foo contains {bar: '#number'}
* match each arrayData.foo contains {bar: '#? _ > 0'}
```

![karate06_each.png](https://qiita-image-store.s3.amazonaws.com/0/22893/b1451e2e-b762-671a-e51b-706e9c00ccca.png)


## スキーマのチェック
`match`コマンドでは、テスト対象データの型や値だけでなく、スキーマによるチェックも可能です。
ここでは、配列を対象に説明しますが、配列の要素数や、配列の中の型などのチェックが可能です。

```cucumber
Scenario: Schema Validation

* def foo = ['bar', 'baz']

# should be an array
* match foo == '#[]'

# should be an array of size 2
* match foo == '#[2]'

# should be an array of strings with size 2
* match foo == '#[2] #string'

# should be null or an array of strings
* match foo == '##[] #string'

# each array element should have a 'length' property with value 3
* match foo == '#[]? _.length == 3'

# should be an array of strings each of length 3
* match foo == '#[] #string? _.length == 3'
```

![karate06_schema_validation.png](https://qiita-image-store.s3.amazonaws.com/0/22893/c5e697f3-1a19-c837-d627-2acf8cbeb18a.png)



# まとめ
Assertの仕方として、前回（#05 Assertions-Matching）の内容から、さらに応用した記述方法を確認しました。
これらの記法を覚えておくと、効率よくテスト実行結果の確認をできますね。