Bendangelo

Ben Avatar

I build apps using Ruby on Rails and AI. Also am fluent in Mandarin Chinese.

Minitest is better than RSpec for AI Agents

Jun 21, 2026 3 minute read

I been using RSpec ever since I started Ruby on Rails development back in 2012. It was basically the default for writing tests in every Rails project, and it made sense because it was more human readable than the default test suite, minitest. But AI agents have changed everything, humans are no longer writing tests. Tests are being written faster, in parallel and – the biggest issue – being ran in parallel.

RSpec has bad test parallel support

I often have 2-3 AI agents running at one time and they almost always finish their task by running the test suite. Because of the way RSpec parallel works, it often breaks when two agents try to run the test suite at the same time. It didn’t made it if the agent was trying to run the whole test suite or even a single file. The supported rails test doesn’t have this problem. It can be ran multiple times and never chocked up an ai agent. This became a real blocker for me, because now I had to baby sit ai agents to make sure they never ran tests at the same time.

RSpec parallel is too slow

It just isn’t as fast as Minitest, maybe this has been known for a long time but because my test suite is over 4500 tests. I need all the speed I can get. This suite takes about 50 mins to complete. I have made plenty of optimizations but it’s just not a priority, if I can get more speed for free then why not. This same test suite on RSpec took well over an hour. An other good reason to move to minitest.

RSpecs syntax is confusing for llms

RSpec was designed for humans writing code, now it’s ai doing it. So it makes more sense for the test style to represent this.

Moving to Minittest was totally worth it

After about a month on minitest, I have no regrets. It has first class support in Ruby on Rails, native parallel testing, and the tests are easier to read.

Include mocha for mocking

The only issue I encountered was lack of stubbing, I ended up including mocha for this.

This is my test group in bundle:

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "minitest-reporters"
  gem "cuprite"
  gem "capybara-lockstep"

  gem 'vcr'
  gem 'webmock'

  # Code coverage with markdown output for LLM consumption
  gem 'simplecov', require: false
  gem 'simplecov-markdown', require: false
  gem 'mocha', '~> 2.7'
end

MinitTest test helper file

Here is my test helper, it should help someone get started:

Minitest::Reporters.use! [
  SingleLineReporter.new
]

FactoryBot.definition_file_paths = [Rails.root.join("test", "factories")]

module ActiveSupport
  class TestCase
    include FixtureScoping
    include ActiveSupport::Testing::TimeHelpers
    include FactoryBot::Syntax::Methods
    include AuthenticationHelpers::Minitest
    include MeilisearchHelpers
    include TenantHelper
    include BulkInsertHelper

    parallelize(workers: :number_of_processors)
    self.test_order = :random

    setup do
      ActsAsTenant.current_tenant = nil
      Current.reset
      ::MeiliSearch::Rails.deactivate!
    end

    teardown do
      ActsAsTenant.current_tenant = nil
      Current.reset
    end
  end
end

I created a custom reporter for llms, it just cuts out the noise and lets the llm only see important info.

Bonus: How to run the full ci for llms

Cause the test suite takes over 50mins to complete. In my AGENTS.md I wrote never run the full test suite, because this will timeout the opencode bash command. So instead I run this ci script and it will log everything to file, then when I’m ready I pipe it into a new opencode session and it starts making it’s fixes. Here is the script:

# bin/ci-log
#!/bin/bash
set -euo pipefail

# Ensure we are in the repo root
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.."

# Setup logging destination
mkdir -p tmp
LOG_FILE="tmp/ci-output.log"

echo "🚀 Starting CI via bin/ci..."

bin/setup --skip-server

# Run bin/ci, pipe stdout/stderr to terminal AND save to file
set +e
bin/ci 2>&1 | tee "$LOG_FILE"
CI_EXIT_CODE=${PIPESTATUS[0]}
set -e

echo "----------------------------------------"
echo "Log saved to: $LOG_FILE"
echo "----------------------------------------"

# Trigger LLM Agent if the Ruby CI script failed
if [ $CI_EXIT_CODE -ne 0 ]; then
  echo "💡 Errors to fix."
else
  echo "✅ CI Passed perfectly."
fi

Comments

You can use your Fediverse (i.e., Mastodon, among many others) account to reply to this post.

Related Posts