Hello! I''m new to Mocha and through experimentation I found out something that is not explicitly stated in the documentation: If you need to mock the same function call with different parameters and results, you can set the scope of expectations with a begin ... end block. I also made up an example on how to expect more than one function call with different parameters and return values. Someday I will have a blog where I can publish this example, for now I send it to the mailing list: # This is the object we will mock class A def m(p) return p+1 end end # This is teh object we will test class B def m(p) a = A.new a.m(p) end def calltwice(p) a = A.new a.m(p+1)+a.m(p+2) end end require ''test/unit'' require ''rubygems'' require ''mocha'' require ''stubba'' class BTest < Test::Unit::TestCase # This test demonstrates how you can call a function that calls a mocked # object more than one time in the same test def test_m_call b = B.new begin A.any_instance.expects(:m).with(5).returns(6) assert_equal 6, b.m(5) end begin A.any_instance.expects(:m).with(9).returns(10) assert_equal 10, b.m(9) end end # This test demonstrates how to mock objects where the method is called # more than one time with different parameters and different results def test_twocall b = B.new params = [6,7] results = [7, 8] e = A.any_instance.expects(:m) e.with {|p| p == params.shift} e.returns(lambda {results.shift}) e.times(2) assert_equal 15, b.calltwice(5) end end
On 02/12/06, Gabriel Birke <gabriel.birke at gmail.com> wrote:> I''m new to Mocha and through experimentation I found out something > that is not explicitly stated in the documentation: If you need to > mock the same function call with different parameters and results, you > can set the scope of expectations with a begin ... end block. > > I also made up an example on how to expect more than one function call > with different parametersThanks for your interest in Mocha. It''s quite likely that some behaviour is not properly documented. I might be missing something, but I don''t see why you wouldn''t write the two tests like this... def test_m_call b = B.new A.any_instance.expects(:m).with(5).returns(6) A.any_instance.expects(:m).with(9).returns(10) assert_equal 10, b.m(9) assert_equal 6, b.m(5) end def test_twocall b = B.new A.any_instance.expects(:m).with(6).returns(7) A.any_instance.expects(:m).with(7).returns(8) assert_equal 15, b.calltwice(5) end I don''t think the begin...end combinations in your first test buy you anything, does it? While your second test is an example of how to use a block with the with() method and a Proc with the returns() method, I don''t see why you wouldn''t just use two expectations as shown above. -- James. http://blog.floehopper.org
Well, I didn''t know you can "stack" expectations this easily - it makes may example somewhat moot. I assumed that each "expect" would override the previous one. Btw, does that mean that each "expect" call adds 1 to the expected number of times the mocked method is called? Gabriel 2006/12/2, James Mead <jamesmead44 at gmail.com>:> Thanks for your interest in Mocha. It''s quite likely that some > behaviour is not properly documented. I might be missing something, > but I don''t see why you wouldn''t write the two tests like this... > > def test_m_call > b = B.new > A.any_instance.expects(:m).with(5).returns(6) > A.any_instance.expects(:m).with(9).returns(10) > assert_equal 10, b.m(9) > assert_equal 6, b.m(5) > end > > def test_twocall > b = B.new > A.any_instance.expects(:m).with(6).returns(7) > A.any_instance.expects(:m).with(7).returns(8) > assert_equal 15, b.calltwice(5) > end > > I don''t think the begin...end combinations in your first test buy you > anything, does it? > > While your second test is an example of how to use a block with the > with() method and a Proc with the returns() method, I don''t see why > you wouldn''t just use two expectations as shown above. > > -- > James. > http://blog.floehopper.org > _______________________________________________ > mocha-developer mailing list > mocha-developer at rubyforge.org > http://rubyforge.org/mailman/listinfo/mocha-developer >-- -- Gabriel Birke CEO describe europe Ltd. http://www.d-scribe.de/
On 02/12/06, Gabriel Birke <gabriel.birke at gmail.com> wrote:> I didn''t know you can "stack" expectations this easily - it makes may > example somewhat moot. > > I assumed that each "expect" would override the previous one. Btw, > does that mean that each "expect" call adds 1 to the expected number > of times the mocked method is called?There are two stages for an expectation, matching and verifying. When a method is called on a mock, it checks through its list of expectations looking for the first matching one. Expectations match based on a combination of the method name and the parameters. If you do not specify any parameters, i.e. no call to with(), the expectation will match any parameters. When an expectation is matched, its count is incremented. At verification time, for each expectation the actual count is compared to the expected count. So if you have two expectations for the same method but with different parameters, each expectation has a default expected count of 1. But you could set different expected counts on each expectation... object.expects(:my_method).with(1).times(1) object.expects(:my_method).with(2).times(2) object.my_method(1) object.my_method(2) object.my_method(2) Does that make sense? One confusing aspect of the behaviour at present is when you specify the same expectation twice with the same parameters - I need to do some work on this... object.expects(:my_method).with(1).returns(1) object.expects(:my_method).with(1).returns(2) object.my_method(1) # => 1 # first expectation passes verification - expected count 1, actual count 1 # second expectation fails verification - expected count 1, actual count 0 I think it makes most sense in this case for the second expectation to override the first... object.my_method(1) # => 2 # first expectation ignored # second expectation passes verification - expected count 1, actual count 1 What do you think? -- James. http://blog.floehopper.org