Reputation: 1321
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).
Upvotes: 16
Views: 10402
Reputation: 655
A simpler version from @Innerpeacer version would be:
User.any_instance.stubs(:can?).with(any_parameters)
User.any_instance.expects(:can?).with('withdraw')
Upvotes: 3
Reputation: 1784
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.
Upvotes: 24
Reputation: 1321
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
Upvotes: 19