aeromock-dockerを使って、APIに依存するアプリケーションのテストをローカルでもCircleCIでも簡単にできるようにする

AeromockのDockerイメージをDocker Hubに公開してみました。

普段からDockerに慣れ親しんでいる人であれば、イメージを落としてきてAeromockのディレクトリをマウントするだけで簡単にモックサーバの機能を利用できます。

Mac環境であればboot2docker環境で利用するわけですが、boot2dockerについてはこの記事の本質じゃないので省略。

通常、Aeromockを使うにはaeromock-brewというツールでインストールするんですが、その手間無しに利用できます。

使い方

サンプルプロジェクトを用意してます。

Aeromock周りの準備
  1. Aeromock用のディレクトリを掘る(/path-to-path/aeromock)
  2. 設定ファイルのproject.yamlを用意(/path-to-path/aeromock/project.yaml
ajax:
  root: ./api_root

static:
  root: ./static
  1. APIのモックデータ用のディレクトリを掘る(/path-to-path/aeromock/api_root)
  2. 静的コンテンツのディレクトリを掘る(/path-to-path/aeromock/static)。必要なくても、現状これが無いと動かない(近いうちに直す)ので、.gitkeepでもディレクトリに放り込んでおく
  3. テストデータを置く(/path-to-path/aeromock/api_root/test.yaml)。test.yamlで置くので、このモックデータのエンドポイントは/testとなる。
hoge: fuga
AeromockをDockerで動かす

Dockerで意識することはマウントするAeromockのディレクトリとポートだけです。dockerコマンドで済ますのであれば以下の通り。

$ docker run -d -p 3183:3183 -v /path-to-path/aeromock:/project stormcat24/aeromock

マウント先は/project(ここは変えないように)。

個人的にはDockerコンテナのオーケストレーションにはFigを使っているので、以下のようにfig.ymlを用意してFig経由で起動するのが良いかなと。Figだとマウント元のパスを相対パス指定できますし。

aeromock:
  image: stormcat24/aeromock
  ports:
    - 3183:3183
  volumes:
    - ./aeromock:/project

FigでAeromock起動

$ fig up -d aeromock

CircleCIでCIする

せっかくDockerを使ってるので、CircleCIでCIしてみましょう。以下のようなcircle.ymlを用意します。

machine:
  timezone: Asia/Tokyo
  services:
    - docker
  pre:
    - sudo sh -c "curl -L https://github.com/docker/fig/releases/download/1.0.1/fig-`uname -s`-`uname -m` > /usr/local/bin/fig"
    - sudo chmod +x /usr/local/bin/fig

dependencies:
  pre:
    - fig up -d

test:
  pre:
    # wait for starting Aeromock
    - sleep 5
  override:
    - curl http://127.0.0.1:3183/test

machineフェーズでFigのダウンロードと設定、dependenciesフェーズでFig経由でAeromockを起動します。

testフェーズではどのようなテストを実行するかを記述するわけですが、ここではAeromockに向けてcurlするだけにしてます。

f:id:a-yamada:20150125211222p:plain

CircleCIでCIしてみると、データファイルで定義した通りのデータが返ってきてることがわかります。

この仕組みを応用すれば、APIを利用するアプリケーションのテストがしやすくなります。grunt-connect-proxyやgulp-webserverのプロキシにAeromockを利用して、ローカルでもCircleCI上でもその環境を意識せずにAPIを利用したテストをすることができるようになります。

APIを利用するアプリケーションのテストは難しいわけで・・・

APIを利用するアプリケーションの場合、ローカルでも開発環境でもCI環境でもシームレスに連携させてテストを通すようにするのは結構難しいものです。

Docker以前の時代では色々な工夫が必要でした。ユニットテスト時にAPIのリクエストを投げないような仕組みにしたり、テスト用のレスポンスを返すようにしたり・・・。(実際にAPIサーバにリクエストしても、そのレスポンスは保証されないし、そもそも死んでるかもしれないし)。

しかし、これらの苦肉の策による方法はテストを通すためにAPIクライアントのテスト(リクエストやレスポンスハンドリング部分)を事実上放棄してるに近く、このようなテストにはそれほど意義がなくなってしまいます。

結合という意味においてはモックサーバを使ったユニットテストにおいてもその意義は問われるかもしれません。ただ、APIのインタフェースを取り決めておき、その仕様ベースで開発が動いているのであれば、CIによってクライアント側のコード品質が保たれることは十分に意味があることと考えます。

Aeromockを使えばAPI仕様には依存しますが、APIサーバというコンポーネントには依存しなくなるので、利用しているAPIサーバにテストで悩まされるということは無くなります。というかそういうのはもう無くしましょう。少なくとも単体レベルにおいては、他のスコープにコンテキストを奪われるような要素はどんどん排していくべきですね!