freerange/mocha: Ruby mocking with an expects and a stubs, and a load order that matters
A mocking and stubbing library for Ruby
At a glance
- What is it?
- Mocha is a Ruby library for mocking and stubbing that keeps to two of the four test double types, deliberately not fakes or spies, and ships adapters for Minitest, Test::Unit, RSpec, Cucumber and Rails. Its setup is mostly about ordering, since the Mocha integration has to be loaded after the test framework it plugs into.
- Who is it for?
- Adopt mocha if your Ruby suite already uses Minitest, Test::Unit or RSpec and you want mock objects with expectation verification rather than a hand rolled stub helper, since the syntax is small and the framework integration is built in. Do not adopt it if you need fakes or test spies, because the project states that it is focused on mocks and stubs and that extending it that way is a deliberate non-goal for now.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 33 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two of the four test double types, on purpose
Mocha is a Ruby library for mocking and stubbing, and the very first bullet of its description is about what it is not. It is deliberately not, yet, faking or spying, linking to the xunitpatterns descriptions of the four test double types.
The intended usage section says the same thing in more detail. Mocha is for the Mock Object and Test Stub types of test double, not for the Fake Object or Test Spy types. The stated reason is focus: although it would be possible to extend Mocha to allow fakes and spies, the project has chosen to keep it focused on mocks and stubs.
That is a small decision with real consequences for a team, because the four types answer different questions. A mock asserts that an interaction happened, with an expectation that must be met. A stub replaces a method with a fixed answer and asserts nothing. A fake is a working implementation, a test spy records calls for later inspection. If your suite leans on spies to assert that a notification was sent, or on fakes to give a service a working in-memory implementation, Mocha is the wrong shape of tool, and no amount of configuration will change that.
What Mocha does offer is a unified, simple and readable syntax for both full and partial mocking, with built-in support for Minitest and Test::Unit, and support from a number of other test frameworks through adapters.
The setup is a load order, and it is the part people get wrong
Installation is a gem:
$ gem install mochaThe important instruction comes next. If you are intending to use Mocha with Test::Unit or Minitest, you should only set Mocha up after loading the relevant test library. The integration is a patch on top of the framework, so it has to be applied to a framework that already exists.
For Test::Unit that is three requires in order:
require 'rubygems'
gem 'mocha'
require 'test/unit'
require 'mocha/test_unit'And for Minitest it is the same shape with a different last line:
require 'rubygems'
gem 'mocha'
require 'minitest/autorun'
require 'mocha/minitest'With Bundler, the gem goes in the Gemfile and the require happens later, once you know the test library has been loaded:
# Gemfile
gem 'mocha'
# Elsewhere after Bundler has loaded gems e.g. after `require 'bundler/setup'`
require 'test/unit'
require 'mocha/test_unit'The general rule for any other framework is stated in the other test framework section: ensure that the relevant Mocha file, `mocha/minitest`, `mocha/test_unit` or `mocha/api`, is required after the test framework has been loaded, for example at the bottom of `test_helper.rb` or `spec_helper.rb`, or at least after `rails/test_help` has been required.
For a Rails application the same advice applies with a note. If you load Mocha through Bundler inside Rails, you should set it up manually, at the bottom of your `test_helper.rb`, and the documentation points out that since Rails v4 `ActiveSupport::TestCase` has inherited from `Minitest::Test` or its earlier equivalents, so unless you are explicitly using Test::Unit you are likely using Minitest.
expects for expectations, stubs for answers
The syntax is the small part of the library, and the quick start shows the whole vocabulary.
class MiscExampleTest < Test::Unit::TestCase
def test_mocking_a_class_method
product = Product.new
Product.expects(:find).with(1).returns(product)
assert_equal product, Product.find(1)
end
def test_mocking_an_instance_method_on_a_real_object
product = Product.new
product.expects(:save).returns(true)
assert product.save
end
def test_stubbing_instance_methods_on_real_objects
prices = [stub(pence: 1000), stub(pence: 2000)]
product = Product.new
product.stubs(:prices).returns(prices)
assert_equal [1000, 2000], product.prices.collect {|p| p.pence}
end
def test_traditional_mocking
object = mock('object')
object.expects(:expected_method).with(:p1, :p2).returns(:result)
assert_equal :result, object.expected_method(:p1, :p2)
end
end`expects` sets an expectation: the method must be called with those arguments, and the mock is verified at the end of the test. `stubs` replaces a method with a return value and makes no demand about whether it was called. `mock('object')` creates a standalone mock object, and `stub(method1: :result1)` is the shortcut form that builds one with named methods.
The `with` argument is what makes a mock useful rather than merely possible, because it is how you say that `find` was called with 1 and not with 2. The mock object example in the documentation makes the verification explicit, with the comment that the expectation is auto-verified at the end of the test.
Partial mocking and any_instance
Full mocking means creating a mock and injecting it. Partial mocking means stubbing a method on a real object or class, which is what the README calls partial mocking, and the documentation illustrates it with an `Order` class whose `total_cost` depends on `total_weight` and `shipping_cost`.
The test then stubs one method and lets the rest of the object run:
class OrderTest < Test::Unit::TestCase
# illustrates stubbing instance method
def test_should_calculate_shipping_cost_based_on_total_weight
order = Order.new
order.stubs(:total_weight).returns(10)
assert_equal 60, order.shipping_cost
end
endThe class method case is the same idea, applied to a singleton method defined inside a `class << self` block, and the quick start also shows the per class variant, `Product.any_instance.stubs(:name).returns('stubbed_name')`, which applies the stub to every instance of the class.
That last form is the one to be careful with, and it is a style question rather than a library question. Stubbing every instance of a class is convenient and blunt: it removes the ability to test that one particular instance behaves differently, and it hides which object under test is actually responsible for a call. Partial mocking on a specific instance keeps the scope tight, and most suites that adopt Mocha end up using the narrower form for that reason.
RSpec, Cucumber and Rails, three different integration shapes
The other frameworks integrate in three quite different ways, and knowing which is which saves time.
RSpec includes a mocha adapter, and you tell RSpec you want to mock with `:mocha`:
# Within `spec/spec_helper.rb`
RSpec.configure do |config|
config.mock_with :mocha
endThere is no require statement needed for the setup, because RSpec does it itself. That is a nicer integration than the others, and it is the model of what a framework with first class adapter support looks like.
Cucumber is the most manual, because a Cucumber step is not a test method and there is no framework to patch. The World object is given the Mocha API and each scenario is wrapped in an around hook that sets up, runs and verifies:
require 'mocha/api'
World(Mocha::API)
Around do |scenario, block|
begin
mocha_setup
block.call
mocha_verify
ensure
mocha_teardown
end
endThe `ensure` block is what guarantees teardown runs even when the step fails, which is the kind of detail that separates a working integration from one that leaks state between scenarios.
Rails is the third case, and it is the one the documentation warns about, because the require has to come after Rails has loaded the test framework itself, and the documentation places it at the bottom of `test_helper.rb`. The instruction is to put the require at the bottom of the file, or at least after `rails/test_help`.
An old known issue and the state of the project
The README carries a known issues section, and the entry is about the distant past. Prior to v1.15.0, when support for Ruby v1.8 was dropped, stubbing an aliased class method where the original method is defined in a module used to `extend` the class did not work in Ruby v1.8, and the README points at the acceptance test that captures the behaviour.
That entry is a useful signal rather than a problem to worry about. A library that documents a bug in a Ruby version it dropped years ago is a library that has been around long enough to have made that decision deliberately, and the fact that the issue is still listed rather than deleted suggests the documentation is maintained rather than copied forward.
The repository layout supports that reading. There is a `lib/` directory for the code, a `test/` tree, a `Rakefile`, a `mocha.gemspec`, a `Gemfile`, a `gemfiles/` directory for testing against multiple dependency sets, a `.rubocop.yml` with a `.rubocop_todo.yml` for the existing offences, a `.yardopts` for the generated API documentation, and separate `docs/`, `CONTRIBUTING.md`, `RELEASE.md`, `MIT-LICENSE.md` and `COPYING.md` files.
The two licence files are worth a note. The project carries an MIT licence file and a separate COPYING.md, and GitHub's own classification of the repository licence is not one it can name, so if you are embedding this in a commercial product, read both files rather than assuming what the badge says.
On release cadence, the project publishes to RubyGems and has no GitHub releases at all, so the version history lives in the gem rather than in the repository tags. The last push to the repository was on 2026-09-22.
Editorial conclusion
Adopt mocha if your Ruby suite already uses Minitest, Test::Unit or RSpec and you want mock objects with expectation verification rather than a hand rolled stub helper, since the syntax is small and the framework integration is built in. Do not adopt it if you need fakes or test spies, because the project states that it is focused on mocks and stubs and that extending it that way is a deliberate non-goal for now. Verify first that the Mocha require happens after your test framework is loaded, since the documentation makes that ordering the rule rather than a suggestion, and that the licence files in the repository, an MIT-LICENSE.md and a COPYING.md, cover the way you intend to use the gem.
Frequently asked questions
How do I install and set up mocha for a Ruby test suite?
Install it with `gem install mocha`, then require the relevant integration file after your test framework is loaded: `require 'mocha/test_unit'` for Test::Unit or `require 'mocha/minitest'` for Minitest. With Bundler, add `gem 'mocha'` to the Gemfile and do the require later, for example at the bottom of `test_helper.rb`.
What is the difference between expects and stubs in mocha?
`expects` sets an expectation that the method is called, optionally with specific arguments via `with`, and the expectation is verified at the end of the test. `stubs` replaces the method with a return value and makes no demand about whether it was called.
Does mocha support fakes and test spies?
No, and that is deliberate. The project describes itself as a library for mocking and stubbing but deliberately not, yet, faking or spying, and says it has chosen to keep it focused on mocks and stubs even though extending it to fakes and spies would be possible.
How do I use mocha with RSpec and with Cucumber?
RSpec ships a mocha adapter, so you set `config.mock_with :mocha` in your spec helper and no require statement is needed. Cucumber needs the Mocha API mixed into the World and an around hook that calls `mocha_setup`, runs the scenario, calls `mocha_verify` and tears down in an ensure block.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/freerange-mocha)Was this useful?