← til

Running parallel Rails tests on Github Actions

January 22, 2021
rails

Since I've already written an article about how to run parallel Rails tests on Heroku CI, I wanted to share how to do it on Github Actions.

Here's a simple way to partition your tests, without using third party services.

# .github/workflows/test.yml
---
name: Test
on: [push]

jobs:
  tests:
    name: Tests
    runs-on: ubuntu-latest

    strategy:
      matrix: 
        # Specify an index for each job ran in parallel
        index: [0, 1, 2, 3, 4]
    steps:
      # ...
      - name: Run tests
        env:
          # Specifies how many jobs you would like to run in parallel,
          # used for partitioning
          NUMBER_OF_NODES: 5
          # Use the index from matrix as an environment variable
          CI_NODE_INDEX: ${{ matrix.index }}
        run: |
          ./bin/test

This will run 5 jobs in parallel and it assumes you have a ./bin/test script for partitioning your tests.

This is how that script looks like:

#!/usr/bin/env ruby

tests = Dir["test/**/*_test.rb"].
  # Add some randomization. Different test order for every run.
  shuffle(random: Random.new(ENV["GITHUB_RUN_ID"])).
  select.
  with_index do |_, i|
    i % ENV["NUMBER_OF_NODES"].to_i == ENV["CI_NODE_INDEX"].to_i
  end

exec "bundle exec rails test #{tests.join(" ")}"

The script assumes you are using Minitest, so replace the rails test with rspec and update the test lookup bit if you're using RSpec.

The downside of this approach is that your tests will not be split based on the duration of tests, so some jobs might take longer than others.