GitHub ActionsでRspec並列実行
strategy matrixを利用して分割を実現する
code:.github/workflows/test.yml
name: test
on:
- pull_request
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
steps:
- uses: actions/checkout@v2
# (略) bundle installとか
- run: |
echo "${{ matrix.parallelism }} ${{ matrix.id }}" | ruby bin/test_splitter.rb | xargs bundle exec rspec
code:bin/test_splitter.rb
parallelism, index = gets.split
# ファイルサイズによる貪欲法
spec_files = Dir.glob("spec/**/*_spec.rb").sort_by { |file| File.size(file) }
puts spec_files.select.with_index { |_, i| i % parallelism == index }.join(' ')
split by timing
CircleCIのように実行時間で分割できないか?
code:rspec.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="rspec" tests="24" skipped="2" failures="16" errors="0" time="0.029023" timestamp="2020-09-20T18:04:52+09:00" hostname="ohbas-MacBook-Pro.local">
<properties>
<property name="seed" value="18273"/>
</properties>
<testcase classname="spec.example_spec" name="some example specs should succeed" file="./spec/example_spec.rb" time="0.001006"></testcase>
<testcase classname="spec.example_spec" name="some example specs should fail" file="./spec/example_spec.rb" time="0.017981"><failure message="
expected true
got false
" type="RSpec::Expectations::ExpectationNotMetError">Failure/Error: expect(false).to be(true)
expected true
got false
./spec/example_spec.rb:10:in `block (2 levels) in <top (required)>'
./spec/spec_helper.rb:7:in `block (2 levels) in <top (required)>'</failure></testcase>
<testcase classname="spec.one_more_spec" name="some example specs can capture stdout and stderr" file="./spec/one_more_spec.rb" time="0.000049"><system-out>Test
</system-out><system-err>Bar
</system-err></testcase>
<testcase classname="spec.one_more_spec" name="some example specs it should behave like shared examples in a shared example succeeds" file="./spec/one_more_spec.rb" time="0.000060"></testcase>
<testcase classname="spec.one_more_spec" name="some example specs it should behave like shared examples in a shared example also fails" file="./spec/one_more_spec.rb" time="0.000086"><failure message="
expected true
got false
" type="RSpec::Expectations::ExpectationNotMetError">Failure/Error: expect(false).to be(true)
expected true
got false
Shared Example Group: "shared examples" called from ./spec/one_more_spec.rb:45
./spec/shared_examples.rb:8:in `block (3 levels) in <top (required)>'
./spec/spec_helper.rb:7:in `block (2 levels) in <top (required)>'</failure></testcase>
</testsuite>
XMLをartifactsとしてstore
次回以降のworkflowでGitHub API叩いてartifacts取得
parseして実行時間ベースで分割する自前スクリプトで分割
code:ruby
require 'rexml/document'
doc = REXML::Document.new(File.new("tmp/rspec.xml"))
summary = {}
doc.root.each_element('//testcase') do |a|
end
p summary
code:shell
{
"./spec/example_spec.rb"=>0.021073000000000005,
"./spec/one_more_spec.rb"=>0.0014189999999999997
}
参考