Project

crspec

0.0
The project is in a healthy, maintained state
Next-generation Ruby test runner using Fiber Storage isolation (Ruby 3.2+), fiber-aware mocks, connection leasing, and Prism AST transpilation.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 0.19.0
 Project Readme

Crspec

Crspec is a next-generation concurrent, fiber-isolated Ruby testing framework ecosystem. By leveraging Ruby 3.2+ Fiber Storage (Fiber[:key]), fiber-aware method interceptors, non-blocking fiber schedulers, and ruby/prism AST transpilation, Crspec achieves ultra-fast concurrent test execution while maintaining full syntax compatibility with traditional RSpec suites.


Key Features

  • Fiber Storage Context Isolation: Solves legacy thread-local (Thread.current) state leakage by routing all execution metadata and let memoization through inherited Fiber storage (Fiber[:crspec_execution_context]).
  • Fiber-Aware Mocking (crspec-mock): Prevents mock registry corruption across parallel tests using prepended method interceptors bound to Fiber[:crspec_mock_space].
  • Rails Integration & ActiveSupport Reuse (crspec-rails): Direct integration with ActiveSupport::Testing::Assertions, ActiveSupport::Testing::TimeHelpers, and ActiveSupport::Testing::FileFixtures. Leases database connections per example fiber (ActiveRecord::Base.lease_connection), handles savepoint transaction strategies (SAVEPOINT ex_root), and integrates with Rails parallel worker suites (Crspec::Rails::Parallel).
  • Rails Request Specs: Expressive HTTP request verb helpers (get, post, put, patch, delete), response status inspection (response.status), headers, and json_response parsing.
  • Prism-Based AST Transpiler (crspec-transpiler): Automated migration tool using ruby/prism C-parser to convert existing RSpec codebases to Crspec syntax and flag thread-unsafe constructs like before(:all).
  • Concurrent Execution Kernel: Multi-threaded worker pool integrated with real-time progress dot formatting and non-blocking fiber schedulers (Async::Scheduler).

Installation

Add crspec to your application's Gemfile:

gem "crspec"

Then install via Bundler (or mise):

bundle install

Spec Helpers & Generator

Initialize standard spec_helper.rb (and rails_helper.rb if run within a Rails project):

 crspec --init

Spec files include helpers explicitly via standard require statements:

require "spec_helper"
# or
require "rails_helper"

Writing Specs

crspec provides a familiar RSpec-style DSL for structuring example groups and expectations:

require "spec_helper"

Crspec.describe User, type: :model do
  let(:valid_attributes) { { name: "Jane Doe", email: "jane@example.com" } }
  subject(:user) { User.new(valid_attributes) }

  it "validates primary attributes" do
    expect(user.valid?).to be(true)
  end

  it "changes user count when created" do
    expect {
      User.create!(valid_attributes)
    }.to change(User, :count).by(1)
  end

  context "when email is omitted" do
    let(:valid_attributes) { { name: "Jane Doe", email: nil } }

    it "flags validation errors" do
      expect(user.valid?).to be(false)
      expect(user.errors[:email]).to include("can't be blank")
    end
  end
end

Supported Matchers

  • eq(expected)
  • be(expected) / be_nil / be_truthy / be_falsy
  • include(*items)
  • raise_error(ExceptionClass, "message")
  • respond_to(*methods)
  • change(receiver, :method).by(amount) / change { ... }.by(amount) / .from(val).to(val)

Advanced: Execution Context & Extensions

Regular spec authors do not need to interact with execution_context at all—crspec automatically isolates let memoization, database connections, and stubs invisibly per test.

For gem developers, middleware, or custom test extension authors needing request tracing across child fibers, execution_context (or current_context) provides an encapsulated, thread-safe store:

before do
  execution_context[:trace_id] = "TX-12345"
end

it "reads execution context metadata" do
  expect(execution_context[:trace_id]).to eq("TX-12345")
end

Fiber-Isolated Mocking (crspec-mock)

crspec-mock routes all doubles and stubs through Fiber[:crspec_mock_space], allowing parallel tests to stub methods on shared target objects without cross-test pollution:

Crspec.describe PaymentGateway do
  let(:stripe_client) { instance_double(Stripe::Charge) }

  it "stubs credit card processing concurrently" do
    allow(stripe_client).to receive(:create).with(amount: 5000).and_return(status: "succeeded")

    result = stripe_client.create(amount: 5000)
    expect(result[:status]).to eq("succeeded")
  end
end

Rails Concurrency & Request Specs (crspec-rails)

Database Isolation & Connection Leasing

rails_helper.rb automatically configures database-independent transaction isolation using your application's config/database.yml:

Crspec.configure do |config|
  config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!
  config.include(Crspec::Rails::RequestHelpers)

  config.around(:each) do |example|
    if defined?(ActiveRecord::Base) && config.use_transactional_fixtures
      Crspec::Rails::DatabaseIsolation.wrap_example(example)
    else
      example.execute!
    end
  end
end

Request Specs

Perform full REST API controller testing with built-in request helpers:

Crspec.describe "Books API", type: :request do
  it "creates a book via POST" do
    post "/books", params: { name: "Refactoring", author: "Martin Fowler" }

    expect(response.status).to eq(201)
    expect(json_response[:name]).to eq("Refactoring")
  end
end

Rails Parallel Testing Setup

Configure worker counts and setup/teardown hooks:

Crspec::Rails::Parallel.parallelize(workers: 4) do
  parallelize_setup do |worker_number|
    puts "Worker #{worker_number} starting"
  end

  parallelize_teardown do |worker_number|
    puts "Worker #{worker_number} tearing down"
  end
end

Migrating from RSpec (crspec-transpile)

Use the built-in Prism-powered transpiler CLI to convert legacy RSpec suites to Crspec:

# 1. Analyze your test directory for thread-unsafe patterns (e.g. before(:all))
crspec-transpile --analyze spec/

# 2. Automatically transpile RSpec code to Crspec syntax in-place
crspec-transpile --write spec/

Sample Rails Bookstore App

Explore the working sample Rails application in samples/book_store:

 ./exe/crspec samples/book_store/spec/

Running Specs

Execute your test suite concurrently using the crspec executable:

# Run specs with default concurrency (number of CPU cores)
crspec spec/

# Run specs with specific concurrency
crspec -c 8 spec/models/

Development & Testing

To run the internal framework unit tests (built with Minitest):

bundle exec rake test

License

The gem is available as open source under the terms of the MIT License.