Seamless migration from third-party mocks to RSpec built-in mocking framework
rspec-mock
is a lightweight gem designed to ease the transition to RSpec's built-in mocking framework by allowing developers to use RSpec's mocks as secondary, alongside a primary, alternative mocking library. This setup enables new code to leverage RSpec’s built-in mocks directly, while still supporting legacy code that relies on an external mocking library.
Table of Contents
- Features
- Requirements
- Installation
- Usage
- Configuration
- Integration
- Migration Analytics
- Contributing
- License
- Code of Conduct
- Credits
- Versioning
- Changelog
Features
- Dual Mocking Compatibility: Use RSpec’s built-in mock framework as a secondary, with your primary mock of choice (e.g., Mocha, FlexMock).
- Seamless Transition: Adopt
RSpec::Mocks
in new tests gradually, without disrupting existing tests dependent on an alternative mocking library. - Simplified Migration Path: Makes it easy to phase out external mocking libraries over time, moving towards a more unified, RSpec-native mocking approach.
Requirements
Ruby MRI 2.4.0+
Installation
Add this line to your application's Gemfile
:
group :test do
gem 'rspec-mock', require: false
end
And then execute:
bundle
Or install it yourself as:
gem install rspec-mock
Usage
Configuration
# spec/support/config/rspec_mock.rb
require 'rspec/mock'
RSpec.configure do |config|
config.rspec_mock do |mock|
mock.verify_partial_doubles = true
end
config.include RSpec::Mock::Methods
end
Integration
# spec/spec_helper.rb
RSpec.configure do |config|
config.mock_framework = :flexmock
end
# spec/sandbox_spec.rb
RSpec.describe Sandbox do
describe '.call' do
subject(:service) { described_class.call(*args, **kwargs) }
let(:args) { [1, 2, 3] }
let(:kwargs) { { a: 1, b: 2 } }
let(:expected_result) { { args:, kwargs: } }
context 'when multiple mocks' do
before do
flexmock(described_class)
.should_receive(:new)
.with(*args, **kwargs)
.pass_thru
rspec_mock do
allow(described_class)
.to receive(:call)
.with(*args, **kwargs)
.and_call_original
end
end
it { is_expected.to eq(expected_result) }
end
context 'when single mock' do
it do
rspec_mock do
expect(described_class)
.to receive(:call)
.with(*args, **kwargs)
.and_call_original
expect(service).to eq(expected_result)
end
end
end
end
end
Migration Analytics
This time implemented migration analytics for Flexmock only. You can run Rake task to analyze Flexmock usage and track migration progress to RSpec mocks.
For non-Rails applications to use the task, you need to load it:
require 'rspec/mock/task'
RSpec::Mock::Task.load
For Rails applications it will be automatically loaded, so just run:
# Analyze entire spec directory (default)
rake rspec_mock:migration_analytics:flexmock
# Analyze specific directory
rake rspec_mock:migration_analytics:flexmock spec/services
# Analyze specific file
rake rspec_mock:migration_analytics:flexmock spec/services/sandbox_service_spec.rb
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/mocktools/ruby-rspec-mock. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct. Please check the open tickets. Be sure to follow Contributor Code of Conduct below and our Contributing Guidelines.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the RSpec::Mock project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
Credits
- The Contributors for code and awesome suggestions
- The Stargazers for showing their support
Versioning
RSpec::Mock uses Semantic Versioning 2.0.0