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

# はじめに
[前回（#04 Defining Data）](https://qiita.com/takanorig/items/1a7920d0dbc2099db000)は、色々なデータの定義の仕方について、確認しました。

今回は、Karate おける Assert の仕方について、確認してみます。
テスト実行時の期待値の確認で利用する内容です。

# Assertの仕方

## Matching
まずは、変数の一致／不一致を確認する内容です。

```cucumber
Scenario: Basic Matching

* def data1 = {name: 'Bob', age: 2}
* def data2 = {age: 2, name: 'Bob'}
* match data1 == data2

* def data3 = {name: 'Bob', age: 2}
* match data3 != {name: 'Bob', age: 3}
```

- ```match A == B``` で、値の一致を確認しています。
- ```match A != B``` は、値の不一致の確認です。

至極、基本的な内容ですね。

![karate05_basic-matching.png](https://qiita-image-store.s3.amazonaws.com/0/22893/b03f9a90-d3cb-9d0e-c8a4-94ab8c5c7849.png)


## Fuzzy Matching 1
Karate では、**「Fuzzy Matching」**と呼ばれている記法があります。
固有の値を指定するのではなく、データの有無や型で判定を行う内容になります。
これを使うと、テストで動的なデータを生成している場合などに便利です。

```cucumber
Scenario: Fuzzy Matching 1

# ignore
* def test = {id: '001', name: { first: 'John', last: 'Smith' }, age: 20}
* match test == {id: '001', name: { first: '#ignore', last: 'Smith' }, age: 20}
```

`#ignore` は、データの比較を無視します。

```cucumber
# null / notnull
* def test = {id: '001', name: null}
* match test == {id: '#notnull', name: '#null'}
```

そのままではありますが、 

- `#null` は **値がnullである** ことの確認
- `#notnull` は **値がnullではない** ことの確認

ですね。

```cucumber
# present / notpresent
* def test = {id: '001', name: 'Bob'}
* match test == {id: '001', name: '#present', age: '#notpresent'}
```

- `#present` は **何かしらの値が存在すること** ことの確認（**値がnullの場合も可**）
- `#notpresent` は **キーを含め、そのパラメータが存在しない** ことの確認

となります。

`#null/#notnull` と `#present/#notpresent` の違いは、以下を確認すると分かりやすいかと思います。

```cucumber
# compare #null/#notnull, ##null/##null, #present/#notpresent
* def foo = { }
* match foo != {a: '#null'}
* match foo == {a: '##null'}
* match foo != {a: '#notnull'}
* match foo == {a: '##notnull'}
* match foo == {a: '#notpresent'}

* def foo = {a: null}
* match foo == {a: '#null'}
* match foo == {a: '##null'}
* match foo == {a: '#present'}

* def foo = {a: 1}
* match foo == {a: '#notnull'}
* match foo == {a: '##notnull'}
* match foo == {a: '#present'}
```

ここでさらに、`##` という記述があります。
`##` は、キーはオプション（存在しないかもしれない）、もしくは、値がnullでも許容する、という意味になります。

これを利用すると、以下のような違いが出てきます。

- `{a: '#null'}` の場合は、キーである`a`は存在していて、値がnullの場合に「True」となります。
- `{a: '##null'}` の場合は、キーである`a`を含めてパラメータ自体存在しないか、値がnullの場合に「True」となります。
- `{a: '##null'}` は、`{a: '#notpresent'}` と同じ意味になります。

ちなみに、`#ignore`、`#null / #notnull`、`#present / #notpresent` などは、**「Marker」**と呼ばれています。

![karate05_fuzzy-matching1.png](https://qiita-image-store.s3.amazonaws.com/0/22893/e0de67d5-b1e7-548f-0b49-86e585f2f6ae.png)


## Fuzzy Matching 2

Fuzzy Matching は、型の特定も可能です。
数値／文字列／bool値だけでなく、配列やオブジェクトなどの型も確認できます。
さらに、正規表現なども指定できます。

```cucumber
Scenario: Fuzzy Matching 2

# number
* def test = {foo: 1}
* match test == {foo: '#number'}

# string
* def test = {foo: 'test'}
* match test == {foo: '#string'}

# boolean
* def test = {foo: true}
* match test == {foo: '#boolean'}

# array
* def test = {foo: [1, 2]}
* match test == {foo: '#array'}

# object
* def test = {foo: {bar: 'baz'}}
* match test == {foo: '#object'}

# regex
* def test = {foo: 'test123'}
* match test == {foo: '#regex [a-z0-9]{7}'}

# uuid
* def test = {id: 'a9f7a56b-8d5c-455c-9d13-808461d17b91'}
* match test == {id: '#uuid'}
```

![karate05_fuzzy-matching2.png](https://qiita-image-store.s3.amazonaws.com/0/22893/6b4e35d7-0cc7-d7a0-7521-b49bf15375d3.png)


## Validation Expressions

`match` では、数式による判定も可能です。
ここまでできれば、かなりチェックの幅も広がります。

```cucumber
Scenario: Validation Expressions

* def month = {value: 3}

* match month == {value: '#? _ > 0 && _ < 13'}

* def min = 1
* def max = 12
* match month == {value: '#? _ >= min && _ <= max'}

* def isValid = function(v) { return v >= 1 && v <= 12 }
* match month == {value: '#? isValid(_)'}
```

![karate05_validation-expressions.png](https://qiita-image-store.s3.amazonaws.com/0/22893/d602bd0e-64e3-66d4-0560-a51916670b39.png)


# まとめ
今回は、単純な値の一致判定だけでなく、Fuzzy Matching／Validation Expressions などの柔軟な判定方法を確認してみました。
これらの判定方法を把握しておけば、大抵のJSONデータは、簡単にチェックができそうです。