コードを1行も書かずにpytestを実行する

# pytest-playとは

## コードを書かずにテストできる

テストコードは必要だけど作るのは大変ですよね。まるで確定申告のようです。
[pytest-play](https://github.com/pytest-dev/pytest-play)はYAMLファイルを書くだけでテストを実行できるライブラリです。
コードを書く必要がないため、プログラマじゃない人にテストの委託もできそうです。

## 機能

下記のような機能があります。

* 実行時間の計測
* JUnit XML report
* StatsD/graphiteを用いたテストメトリクスの監視
* プラグイン
  - play_selenium
  - play_requests
  - play_sql
  - play_cassandra
  - play_dynamodb
  - play_websocket
  - play_mqtt

play_requestsやplay_seleniumを使うと、DjangoやFlaskなどのWebサーバのテストが行なえます。WebサーバはPython製である必要もなく、Railsなどで作られたWebサーバでも構いません。

# インストール

pipでインストールします。

```bash
pip install pytest-play
```

Pythonがインストールされていない環境でも、Dockerから実行できます。

```bash
docker run -i --rm -v $(pwd):/src davidemoro/pytest-play
```

# 使ってみる

簡単なテストをしてみます。pytestと同様に`test`で始まるファイル名のYAMLファイルがテスト対象となります。

```yaml:test_add.yml
- comment: 足し算のテスト
  provider: python
  type: assert
  expression: "1 + 1 == 2"
```

上記の`test_add.yml`を作成してテストを実行します。`pytest`コマンドがそのまま使えます。

```console
$ pytest 
======================================== test session starts =========================================
platform linux -- Python 3.6.7, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /home/driller/work/pytest-play, inifile:
plugins: variables-1.7.1, play-2.2.0
collected 1 item                                                                                     

test_add.yml .                                                                                 [100%]

====================================== 1 passed in 0.05 seconds ======================================
```

YAMLの設定項目を大雑把に説明するとこんな感じです。

* provider: 実行するコマンドを指定します、`python`や`selenium`などがあります
* type: providerのサブカテゴリのようなものです（うまく説明できない）
* expression: 評価式を渡します
* comment: コメントです

## 変数

`type`に`store_variable`、`name`に変数名、`expression`に値を指定します。
`expression`はクォートで囲む必要があります。

```yaml:test_var.yml
- comment: 変数を代入
  provider: python
  type: store_variable
  name: spam
  expression: "'ham'"
- comment: 変数をテスト
  provider: python
  type: assert
  expression: "'$spam' * 2 == 'hamham'" 
```

```console
$ pytest 
======================================== test session starts =========================================
platform linux -- Python 3.6.7, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /home/driller/work/pytest-play, inifile:
plugins: variables-1.7.1, play-2.2.0
collected 2 items                                                                                    

test_add.yml .                                                                                 [ 50%]
test_var.yml .                                                                                 [100%]

====================================== 2 passed in 0.06 seconds ======================================
```

## requestsを使ったテスト

requestを使ってWebサイトのテストをする場合には[play_requests](https://github.com/davidemoro/play_requests)をインストールします。

```bash
pip install play_requests
```

例として、[Weather Hacks](http://weather.livedoor.com/weather_hacks/)のAPIをテストしてみます。
インストールした`play_requests`を`provider`に指定します。
`city=040020`は宮城県白石市のIDです。`pinpointLocation`の最初には`仙台市西部`が入っていることをテストします。

```yaml:test_weather_hacks.yml
- comment: 白石市の天気
  provider: play_requests
  type: GET
  url: http://weather.livedoor.com/forecast/webservice/json/v1?city=040020
  assert: response.status_code == 200
  variable: json
  variable_expression: response.json()
- comment: "json"
  type: assert
  provider: python
  expression: "variables['json']['pinpointLocations'][0]['name'] == '仙台市西部'"
```

```console

$ pytest 
======================================== test session starts =========================================
platform linux -- Python 3.6.7, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /home/driller/work/pytest-play, inifile:
plugins: variables-1.7.1, play-2.2.0
collected 3 items                                                                                    

test_add.yml .                                                                                 [ 33%]
test_var.yml .                                                                                 [ 66%]
test_weather_hacks.yml .                                                                       [100%]

====================================== 3 passed in 0.20 seconds ======================================
```

## seleniumを使ったテスト

[play_selenium](https://github.com/davidemoro/play_selenium)を使います。
インストール方法は同じですが、別途[Webdriver](https://github.com/mozilla/geckodriver/releases)が必要になります。

```bash
pip install play_selenium
```

例としてgoogle.comに検索ワードを入力してみます。

```yaml:test_google.yml
- comment: Google.comにアクセス
  provider: selenium
  type: get
  url: https://google.com
- comment: 検索ワードを入力
  type: setElementText
  provider: selenium
  locator:
    type: name
    value: q
  text: "cp932撲滅"
- type: sendKeysToElement
  provider: selenium
  locator:
    type: name
    value: q
  text: ENTER
- comment: 画面をじっくり眺める時間
  type: pause
  provider: selenium
  waitTime: 10000
```

```console
$ pytest 
======================================== test session starts =========================================
platform linux -- Python 3.6.7, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
rootdir: /home/driller/work/pytest-play, inifile:
plugins: variables-1.7.1, splinter-2.0.1, pypom-navigation-2.0.3, play-2.2.0
collected 4 items                                                                                    

test_add.yml .                                                                                 [ 25%]
test_google.yml .                                                                              [ 50%]
test_var.yml .                                                                                 [ 75%]
test_weather_hacks.yml .                                                                       [100%]

===================================== 4 passed in 14.53 seconds ======================================
```

実行するとブラウザが起動して検索結果の画面が表示されます。

# 雑感

ざっと使ってみた感想としては、コードを書く手間が省けることよりも、YAMLにすることで見た目がすっきりするというのが利点のように感じました。
紹介していない機能がたくさんありますが、機会があれば紹介したいと思います。