ssig33.com

TravisCI で粗雑にテストを分割実行する

テストの分割実行というのは昔からあるテーマで、国内だと cookpad さんの rrrspec は長期間安定して運用し成功している事例として知られています。

ただこれらのプロダクトは導入も運用もめんどくさく、もうちょっと簡単にテストを分割実行したいと僕は前から考えていました。

そこで AWS CodeBuild について以前から注目して導入の検証なども行ないましたが、例えば自分が退職したとかいきなり爆死したとかなった時に今いる会社の残ったメンバーでそれをメンテし続けることは、いやまあ不可能ではないんでしょうけど負担が大きいと言わざるを得ないと判断しました。

Google CodeBuild は AWS CodeBuild よりも実用性が高そうと思ってやっていけるか考えていますが結論がでるのにあと 600 時間ぐらいはかかりそうです。

こうなると TravisCI などを使いつつそこそこの並列度でテストを実行する必要があります。そこで僕はユビレジという会社で以下のような革新的な技法を導入しました。実際に運用されている設定、コードの断片をご覧ください。

Rakefile には以下のように書いています。

  (1..3).each do |i|
    task :"features_#{i}" do
      Dir.glob("#{Rails.root}/features/**/*.feature").sort_by{|x| File::Stat.new(x).size }.reject.with_index{|x,i2| i2 % 3 == i-1 }.each(&FileUtils.method(:rm))
      sh "./bin/rake parallel:features:with_retry"
    end
  end


  (1..3).each do |i|
    task :"test_#{i}" do
      Dir.glob("#{Rails.root}/test/**/*_test.rb").reject{|x| x =~ /test\/support/ }.reject.with_index{|x,i2| i2 % 3 == i - 1}.each(&FileUtils.method(:rm))
      sh "./bin/rake parallel:test"
    end
  end

.travis.yml のほうは以下のようになっています

jobs:
  include:
  - stage: setup
    install: skip
    env:
      - PARALLEL_TEST_PROCESSORS=4 
    script: 
    - make setup
  - stage: test
    env: 
      - PARALLEL_TEST_PROCESSORS=4 
      - TEST_SUITE="parallel:test_1"
    script:
    - make test
  - stage: test
    env: 
      - PARALLEL_TEST_PROCESSORS=4 
      - TEST_SUITE="parallel:test_2"
    script:
    - make test
  - stage: test
    env: 
      - PARALLEL_TEST_PROCESSORS=4 
      - TEST_SUITE="parallel:test_3"
    script:
    - make test
  - stage: test
    env:
      - PARALLEL_TEST_PROCESSORS=3 
      - TEST_SUITE="parallel:features_1"
    script:
    - make test
  - stage: test
    env: 
      - PARALLEL_TEST_PROCESSORS=3 
      - TEST_SUITE="parallel:features_2"
    script:
    - make test
  - stage: test
    env:
      - PARALLEL_TEST_PROCESSORS=3 
      - TEST_SUITE="parallel:features_3"
    script:
    - make test

もうこれ出オチに近いんですが要点を一つ解説しておきます。このような方法でテスト実行の並列度を上げると当然依存ライブラリとかデータベースとか JavaScript のコンパイルとかのセットアップフェーズの時間が無駄になってきます。

これをどうにかする必要があるのですが、 TravisCI には Build Stages という機能があり、ここにいろいろと押し込んでおくと楽です。

ここでは assets:precompile の結果と gem install の結果と ./bin/rails db:setup の結果を mysqldump したものを tar にまとめて s3 に渡すという形で setup フェーズと test フェーズの間で成果物を受け渡すようにしています。

CircleCI の pipeline とかだとこの辺の仕組みもうちょっとマシだったりするんでしょうか。 Docker イメージ経由でやり取りする感じ?このへんはよく知りません。

誰でも一目みれば分かる単純な仕組みでそこそこにテストを分散して実行できるのでオススメです。

back to index of texts


Site Search

Update History of this content