Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocha: How to add expectation of a method when there are multiple invocations with different parameters

I have a Rails controller action to test. In that action, a method User.can? is invoked several times with different parameters. In one of the test case for it, I want to make sure that User.can?('withdraw') is invoked. But I don't care about invocations of User.can? with other parameters.

def action_to_be_tested
  ...
  @user.can?('withdraw')
  ...
  @user.can?('deposit')
  ...
end

I tried below in the test:

User.any_instance.expects(:can?).with('withdraw').at_least_once.returns(true)

But the test failed with message indicating unexpected invocation of User.can?('deposit'). If I add another expectation with parameter 'deposit', the test passed. But I am wondering if there are any ways such that I could just focus on the invocation with 'withdraw' parameter (because other invocations are irrelevant to this test case).

like image 913
Innerpeacer Avatar asked Mar 28 '12 00:03

Innerpeacer


2 Answers

You can pass a block to with and have that block inspect the arguments. Using that, you can construct a list of expected invocations:

invocations = ['withdraw', 'deposit']
User.any_instance.expects(:can?).at_most(2).with do |permission|
  permission == invocations.shift
end

Each time can? is called, Mocha will yield to the block. The block will pull the next value off the list of expected invocations and check it against the actual invocation.

like image 139
Erin Call Avatar answered Oct 22 '22 07:10

Erin Call


I just found a workaround, by stubbing out invocations with irrelevant parameters:

User.any_instance.expects(:can?).with('withdraw').at_least_once.returns(true)
User.any_instance.stubs(:can?).with(Not(equals('withdraw')))

http://mocha.rubyforge.org/classes/Mocha/ParameterMatchers.html#M000023

like image 36
Innerpeacer Avatar answered Oct 22 '22 06:10

Innerpeacer