The letter A styled as Alchemists logo. lchemists
Published February 10, 2025 Updated May 13, 2026
Cover
RSpec Configuration

Multiple paths exist for configuring RSpec. For example, when using bundler gem demo to build a demo gem, you’ll end up with the following configuration:

RSpec.configure do |config|
  config.example_status_persistence_file_path = ".rspec_status"
  config.disable_monkey_patching!

  config.expect_with :rspec do |c|
    c.syntax = :expect
  end
end

This isn’t ideal due to being extremely bare bones. Another example is when using Hanami to build a demo application via hanami new demo:

RSpec.configure do |config|
  config.disable_monkey_patching!
  config.shared_context_metadata_behavior = :apply_to_host_groups
  config.filter_run_when_matching :focus
  config.example_status_persistence_file_path = "spec/examples.txt"
  config.profile_examples = 10
  config.order = :random

  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

  if config.files_to_run.one?
    config.default_formatter = "doc"
  end

  Kernel.srand config.seed
end

The above gets us closer to a more robust configuration but is still missing a few conveniences and checks. Here’s what’s produced when using Rubysmith:

RSpec.configure do |config|
  config.color = true
  config.disable_monkey_patching!
  config.example_status_persistence_file_path = "./tmp/rspec-examples.txt"
  config.filter_run_when_matching :focus
  config.formatter = ENV.fetch("CI", false) == "true" ? :progress : :documentation
  config.order = :random
  config.shared_context_metadata_behavior = :apply_to_host_groups
  config.warnings = true

  config.expect_with :rspec do |expectations|
    expectations.syntax = :expect
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_doubled_constant_names = true
    mocks.verify_partial_doubles = true
  end

  Kernel.srand config.seed
end

With the above in mind, we can break down what each configuration is doing and why it’s important.

Table of Contents

Breakdown

Some of the above configuration might not make sense or be initially intuitive without studying the docs so here’s a line-by-line breakdown.

config.color = true

Ensures output is colorized for improved readability.

config.disable_monkey_patching!

By default, RSpec will monkey patch your environment which leads to confusion and lack of debugability so keep this disabled so you can use RSpec.describe instead of describe when defining your specs.

config.example_status_persistence_file_path = "./tmp/rspec-examples.txt"

Ensures spec status is written to file so you can quickly fix or refactor broken code. This is a major boon to productivity since having this file allows you to run commands like rspec --only-failures or rspec --next-failure.

config.filter_run_when_matching :focus

Ensures you can add focus: true or :focus (shorthand), or fdescribe/fit (even shorter shorthand) when running only focused tests.

config.formatter = ENV.fetch("CI", false) == "true" ? :progress : :documentation

Ensures RSpec formats output in compressed/dotted progress when running on CI because you generally don’t need verbose output in that environment. On the flip side, you’ll get full documentation when running locally so you can debug any spec failure with enough context to help you quickly resolve the issue.

config.order = :random

Ensures all specs are run in random order to ensure no spec depends upon another. Catching this early and often reduces any surprises when changes are deployed in production.

config.shared_context_metadata_behavior = :apply_to_host_groups

Ensures the host group and examples inherit metadata from the shared context. This will be the default in RSpec 4.0.0.

config.warnings = true

Ensures all Ruby warnings are displayed. This can be quite verbose for some folks but is incredible powerful in finding and detecting issues early and often. You’ll also find that some upstream gem dependencies, sadly, do not adhere to this level of rigor. If that’s the case, I’d recommend installing the Warning gem to filter out and silence bad actors or remove those dependencies entirely.

config.expect_with :rspec do |expectations|
  expectations.syntax = :expect
  expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end

The first line ensures you always use expect instead of the should syntax for consistent expectations. The second line ensures custom matcher descriptions — and failure messages — include clauses from defined methods which use chain. Use of chain is not recommended but if it is used, at least you’ll get more descriptive diagnostic information.

config.mock_with :rspec do |mocks|
  mocks.verify_doubled_constant_names = true
  mocks.verify_partial_doubles = true
end

Ensures that doubles — both constants and objects — are properly verified, exist, and haven’t changed which would cause faulty specs, if otherwise. You definitely want both of these enabled so RSpec has your back when using RSpec Test Doubles.

Kernel.srand config.seed

Conclusion

You’ve learned there are multiple ways to configure RSpec and how you can tweak for your own preferences. You’ve also learned what each setting is and why each setting is important. By ensuring you have a solid configuration in place, you can let RSpec work for you and not the other way around.