Baleen: Dockerを使ってCucumberテストを並列で走らせるgemを作ってみた

Cucumberテストの実行に時間がかかりすぎていませんか？時々ランダムで発生するテストエラーに悩んだことはありませんか？

僕はどちらの経験もあります。解決方法は沢山あると思いますが、要は以下のことを実現すればいいわけです。

**各テストの独立性**
一つのテストが他のテストに影響を与えてはいけない。

**テストの並列実行**
各テストは関係を持たないので、並列で実行できるはずです。並列で実行すれば、逐次実行よりも短い時間でテストを実行できます。

独立性は本来、そうなるようにテストを書くべきですが、並列実行は外部のツール(parallel_tests)とかを使わないとどうしようもありません。

そこで、[Baleen](https://github.com/kimh/baleen)というgemを作ってみました。

BaleenはDockerにあなたのcucumberテストを並列で実行させます。ひとつのコンテナに一つのcucumberファイルを実行させ、それを並列で行います。

## インストール
これはgithubのページを見てもらったほうが早いです。

[Baleenのインストール](https://github.com/kimh/baleen#installation)
[Dockerをbaleen用にする](https://github.com/kimh/baleen#try-baleen)

## 準備
#### テスト実行用のDockerイメージ
機能を試すまえに少しだけ準備が必要です。第１にテストを実行するためのDockerイメージを用意しないといけません。イメージはテストしたいcucumberのファイルとcucumberの実行環境が必要です。

つまり、テスト用のイメージは例えば以下のコマンドが実行できないといけません。

```bash
docker run -d my-test-runner /bin/bash bundle exec cucumber features/
```

なぜなら、baleenはfeatures配下にある各ファイルをひとつのコンテナに割り当てて実行するからです。
つまり *features/* に３つのテストファイルがあった場合、裏ではbaleenは以下を実行します。

```bash
docker run -d my-test-runner /bin/bash bundle exec cucumber features/test1.feature
docker run -d my-test-runner /bin/bash bundle exec cucumber features/test2.feature
docker run -d my-test-runner /bin/bash bundle exec cucumber features/test3.feature
```

### baleen-serverの起動
Baleenはサーバ/クライアントモデルをとります。なので、baleen-serverを起動していないといけません。サーバはDockerがインストールされているマシンで起動してもいいですし、クライアントマシンにインスールしてもいいです。

もし、Dockerと同じマシンで動かす場合は、

```bash
baleen-server start
```
でOKです。もし、Dockerが他のマシンで動いている場合は、指定してください。

```bash
baleen-server start --docker-host 192.168.1.100
```

## 機能
### コマンドライン
一番シンプルなcucumberテストを実行する方法はbaleenコマンドを使うやり方です。

```bash
baleen cucumber --image my-test-runner --files features
```

もし、baleen serverをクライアントとは違うマシンで動かしている場合は、 *--baleen_server* をで指定してください。

```bash
baleen cucumber --image my-test-runner --files features --baleen_server 192.168.1.100
```

cucumberを実行する前に何かコマンドを実行する必要がありますか？その時は、 *--before_command* の後に実行したいコマンドを書いてください。

```bash
baleen cucumber --image my-test-runner --files features --before_command "git pull && cd project_dir && bundle install"
```

デフォルトではbaleenはコンテナを３つ同時に起動してテストを実行します。もし、これを変えたい場合は、 *--concurrency* で変更できます。

```bash
baleen cucumber --image my-test-runner --files features --concurrency 6
```

### プロジェクト
cucumberテストを実行する別の方法はクライアントからbaleen projectを使う方法です。プロジェクトはymlファイルに事前に実行したいテストの詳細を書いてbaleen serverにロードしておき、クライアントは実行したプロジェクトを単に呼ぶだけです。こうすることで、いちいちbaleenクライアントからオプションを指定する必要はありません。

まず、以下のようなYAMLファイルを用意します。

```yaml
my-app:
  runner:
    image: "my-test-runner"
    work_dir: /my-home
    concurrency: 3
    before_command: |
      git pull
      cd my-project
      bundle install

  # Framework section
  framework:
    type: cucumber
    features: ./features
```

次にbaleen serverをYAMLの場所を指定して起動します。

```bash
baleen-server start --project_file /path/to/baleen.yml
```

これでプロジェクトがbaleen serverにロードされました。クライアントからはプロジェクト名を指定するだけです。

```bash
baleen project my-app
```

### 他にも
あんまりテストされていない or 実装中の機能を簡単に紹介します。

**CI機能**
githubのpost hookにbaleen CIの待ち受けURLを指定することで自動でテストを実行する機能です。

**バックエンド**
テストを実行するコンテナとは別に、テストが必要とするサービスを提供するためのコンテナを別に立ち上げます。これを使えば、テスト用のDBコンテナを起動して、テストコンテナはDBへのアクセスはDBコンテナを使うことができます。

##まとめ##
以上簡単ですが、baleenの紹介でした。まだまだα以前の完成度ですが、Dockerを使ってRubyテストを実行したい方は試してみてください。