Ruby mocha

From wikinotes

mocha is library that provides tools to mock for ruby.
It adds methods like expects, with, and returns to objects.

Documentation

api docs https://mocha.jamesmead.org/
github https://github.com/freerange/mocha
mock api docs https://mocha.jamesmead.org/Mocha/Mock.html

Basics

Magically adds methods to all classes/instances.

Class
  [ .any_instance() ]                                 # applies to methods of all instances
  [ .expects(:method_name) | .stubs(:method_name) ]   # mocks or stubs classmethod (unless any_instance)
  [ .with(*args) ]
  [ .returns("value") ]

instance
  [ .expects(:method_name) | .stubs(:method_name) ]   # mocks or stubs instancemethod
  [ .with(*args) ]
  [ .returns("value") ]

mock_obj = mock.tap { |m| m.expects(:method_name) }   # mock objects

# useful methods
.expects(:method_name)
.expects(:method_name).twice
.with(*args)
.raises(ArgumentError)
.returns('foo')

Mocks

Dummy objects that expect that method name is called.
Returns canned response, optionally validates called-with-args.

See https://github.com/freerange/mocha#mock-objects

class methods

Product               # class method
  .expects(:save)
  .returns(true)

Product               # mock specific params
  .expects(:find)
  .with(1)
  .returns(product)

instance methods

product = Product.new

product               # instance method
  .expects(:save)
  .returns(true)

Product.any_instance  # instance-method for all instances of Product
  .expects(:name)
  .returns('stubbed_name')

Stubs

Dummy objects whose methods give canned responses.

product = Product.new
product.stubs(:prices).returns(prices)

Complex Mocks/Stubs

Multiple with() calls with different params

User
  .with(a: 1, b: 2).returns(3)
  .with(a: 1, b: 3).returns(4)
  .with(a: 1, b: 4).returns(5)

# alternatively, this works as well
[2, 3, 4].each do |num|
  User.with(a: 1, b: num)
end

Different returns() values for each invocation

User.expects(:name).returns("alex", "courtney", "sam")
User.name # "alex"
User.name # "courtney"
User.name # "sam"

Raise Exception then Return

User.any_instance
  .expects(:speak)
  .twice
  .raises(InvalidLanguageError)
  .then.returns(true)

Message Chains

You can also mock/stub chains of method calls.

User.any_instance
  .stubs(:do_something)
  .returns(stub(sub_method_a: 1,
                sub_method_b: 2))

user = User.new
user.do_something.sub_method_a  #> 1
user.do_something.sub_method_b  #> 2

Target Methods

stub.tap do |s|
  s.stubs(:[]).with(:friend).returns(User.find(1))
  s.stubs(:[]).with(:parent).returns(User.find(2))
  s.stubs(:[]).with(:spouse).returns(User.find(3))
end