0.0
No release in over 3 years
A command-line tool that automatically converts RSpec's `let` and `let!` declarations to `let_it_be` where it's safe to do so.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

~> 1.3
~> 1.4
 Project Readme

be-let-it-be

Ruby Gem Version

A command-line tool that automatically converts RSpec's let and let! declarations to let_it_be where it's safe to do so. The tool runs your tests after each conversion to ensure they still pass, making the optimization process safe and reliable.

Motivation

One of the main motivations is to improve test speed.

What is let_it_be?

let_it_be is a helper provided by the test-prof gem that caches test data across examples instead of recreating it for each test. This can significantly improve test performance, especially for expensive object creation like database records.

Performance Benefits

Using let_it_be can significantly improve test performance by:

  • Reducing database queries
  • Minimizing object instantiation overhead
  • Sharing immutable test data across examples

Performance gains are especially noticeable with:

  • Factory-created database records
  • Complex object initialization
  • Large test suites

How It Works

  1. Parse: Analyzes your RSpec file using Ruby's Abstract Syntax Tree
  2. Identify: Finds all let and let! declarations
  3. Convert & Test: For each declaration:
  • Converts it to let_it_be
  • Runs your tests
  • Keeps the change if tests pass, reverts if they fail
  1. Save: Writes the successfully converted file, or it outputs the result if it's in dryrun mode

Example Conversion

Before:

RSpec.describe User do
  let!(:admin) { create(:user, admin: true) }
  let(:user) { create(:user) }
  let(:posts) { user.posts }
  let(:mutable_array) { [] }

  it "modifies the array" do
    mutable_array << 1
    expect(mutable_array).to eq([1])
  end
end

After:

RSpec.describe User do
  let_it_be(:admin) { create(:user, admin: true) }
  let_it_be(:user) { create(:user) }
  let(:posts) { user.posts }  # Kept as 'let' due to dependency
  let(:mutable_array) { [] }  # Kept as 'let' because tests modify it

  it "modifies the array" do
    mutable_array << 1
    expect(mutable_array).to eq([1])
  end
end

Installation

Add this line to your application's Gemfile:

group :development, :test do
  gem 'be-let-it-be'
end

And then execute:

$ bundle install

Or install it yourself as:

$ gem install be-let-it-be

Prerequisites

  • Ruby 3.3.0 or higher
  • Your project must have test-prof installed, as let_it_be is a feature provided by that gem

Usage

Basic Usage

Convert a single spec file:

be-let-it-be convert spec/models/user_spec.rb

Options

  • --dryrun - Show what would be converted without making actual changes
  • --dryrun-exit-code - Exit code to use in dryrun mode when any convertible declarations are present (default: 1)
  • --verbose - Display detailed processing information
  • --rspec_cmd - Customize the RSpec command used for verification (default: "rspec")

Examples

# Dry-run to preview changes
be-let-it-be convert spec/models/user_spec.rb --dryrun

# Verbose output for debugging
be-let-it-be convert spec/models/user_spec.rb --verbose

# Use custom RSpec command
be-let-it-be convert spec/models/user_spec.rb --rspec_cmd="rspec --format progress"

When NOT to Use let_it_be

The tool automatically detects when conversions would break tests, but it's good to understand when let_it_be isn't appropriate:

  • Mutable objects: When tests modify the object state
  • Test-specific state: When the value depends on test-specific setup
  • Fresh instances: When each test requires a completely new instance

Current Limitations

  • Originally, the replacement of let and let! should adopt the combination that provides the most optimized execution time. However, attempting to do so would likely cause combinatorial explosion, making it non-trivial to implement. Therefore, we currently use a simple approach of replacing them in order of appearance. We plan to address this optimization in the future.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests.

To install this gem onto your local machine, run bundle exec rake install.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/moznion/be-let-it-be. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

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

Code of Conduct

Everyone interacting in the be-let-it-be project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.