Hi folks. I''ve just started using rspec and I have to say it''s very nice. The thing is, I prefer mocha''s mocking dialect. So I thought a simple require ''mocha'' would set me up. Unfortunately, rspec does all its goodness using do/end blocks in anonymous classes, so it wasn''t quite that obvious. Anyway, here is the incantation I ended up using in my equivalent of a test_helper.rb file that I include in all my spec files: # replace rspec''s mocks with mocha require ''mocha'' module Spec module Mocks remove_method :mock remove_method :stub remove_method :verify_mocks if method_defined? :verify_mocks include Mocha::AutoVerify end end Now I have working mock(), stub() and verify_mocks(). Not sure what other Mocha stuff I''m missing yet, but I''ll let you know how I get on. I noticed that Mocha::Standalone also references Mocha::SetupAndTeardown, but I didn''t see anything in there that seemed relevant to rspec mocking. Cheers, Dan
On 12/03/07, Dan North <dan at tastapod.com> wrote:> > I''ve just started using rspec and I have to say it''s very nice. The > thing is, I prefer mocha''s mocking dialect. So I thought a simple > require ''mocha'' would set me up. > > Unfortunately, rspec does all its goodness using do/end blocks in > anonymous classes, so it wasn''t quite that obvious. > > Anyway, here is the incantation I ended up using in my equivalent of a > test_helper.rb file that I include in all my spec files: > > # replace rspec''s mocks with mocha > require ''mocha'' > module Spec > module Mocks > remove_method :mock > remove_method :stub > remove_method :verify_mocks if method_defined? :verify_mocks > include Mocha::AutoVerify > end > end > > Now I have working mock(), stub() and verify_mocks(). Not sure what > other Mocha stuff I''m missing yet, but I''ll let you know how I get on. > > I noticed that Mocha::Standalone also references > Mocha::SetupAndTeardown, but I didn''t see anything in there that seemed > relevant to rspec mocking.Hi Dan, I''m glad you like Mocha''s mocking dialect. It''s great you''ve got Mocha working with RSpec. Mocha::Standalone was an early attempt at simplifying integration with other testing frameworks prompted by a request from the RSpec community. Work on this ground to a halt when RSpec developed their own mocking functionality. Mocha::SetupAndTeardown is to do with what RSpec call partial mocks i.e. where you are mocking a method on a concrete class or object. Looking at what you''ve done, I suspect you will still be able to setup expectations like this but (a) they won''t be verified and (b) the concrete class or object won''t be returned to its original state (Mocha temporarily messes with the method implementation). Let us know if there are any changes we can make that would make the integration easier. -- James. http://blog.floehopper.org
Yes you''re right - it doesn''t automagically verify, but the verify_mocks method is in scope and I like to have that explicitly in my spec methods anyway. The big things on my wishlist are: 1. Matchers in with(..) like JMock has: expects(:chew).with(is_a(Chewable), ANYTHING) where is_a(..) is a [something] that responds to matches?(actual) with true/false, and ANYTHING is a matcher that always returns true. That way, you could use rspec''s expectation matcher framework or roll your own matchers. (I''ve got a bunch I wrote for my own mocking framework - everyone should write a mocking framework at least twice once :) The method matches?(actual) seems fairly universal across these frameworks. 2. Type-aware mocks that fail with a NoMethodError if the underlying type doesn''t respond to an invoked method or method_missing (see earlier thread). 3. Something akin to after(another_mock, :method). None of these are showstoppers, but 1 is really high on my priorities and 2 and 3 would make my life happier. I might try to roll something for 1 if I get the time (read: unlikely!). Cheers, Dan James Mead wrote:> On 12/03/07, Dan North <dan at tastapod.com> wrote: > >> I''ve just started using rspec and I have to say it''s very nice. The >> thing is, I prefer mocha''s mocking dialect. So I thought a simple >> require ''mocha'' would set me up. >> >> Unfortunately, rspec does all its goodness using do/end blocks in >> anonymous classes, so it wasn''t quite that obvious. >> >> Anyway, here is the incantation I ended up using in my equivalent of a >> test_helper.rb file that I include in all my spec files: >> >> # replace rspec''s mocks with mocha >> require ''mocha'' >> module Spec >> module Mocks >> remove_method :mock >> remove_method :stub >> remove_method :verify_mocks if method_defined? :verify_mocks >> include Mocha::AutoVerify >> end >> end >> >> Now I have working mock(), stub() and verify_mocks(). Not sure what >> other Mocha stuff I''m missing yet, but I''ll let you know how I get on. >> >> I noticed that Mocha::Standalone also references >> Mocha::SetupAndTeardown, but I didn''t see anything in there that seemed >> relevant to rspec mocking. >> > > > Hi Dan, > > I''m glad you like Mocha''s mocking dialect. It''s great you''ve got Mocha > working with RSpec. > > Mocha::Standalone was an early attempt at simplifying integration with other > testing frameworks prompted by a request from the RSpec community. Work on > this ground to a halt when RSpec developed their own mocking functionality. > > Mocha::SetupAndTeardown is to do with what RSpec call partial mocks i.e. > where you are mocking a method on a concrete class or object. Looking at > what you''ve done, I suspect you will still be able to setup expectations > like this but (a) they won''t be verified and (b) the concrete class or > object won''t be returned to its original state (Mocha temporarily messes > with the method implementation). > > Let us know if there are any changes we can make that would make the > integration easier. >
On 3/13/07, James Mead <jamesmead44 at gmail.com> wrote:> On 12/03/07, Dan North <dan at tastapod.com> wrote: > > > > I''ve just started using rspec and I have to say it''s very nice. The > > thing is, I prefer mocha''s mocking dialect. So I thought a simple > > require ''mocha'' would set me up. > > > > Unfortunately, rspec does all its goodness using do/end blocks in > > anonymous classes, so it wasn''t quite that obvious. > > > > Anyway, here is the incantation I ended up using in my equivalent of a > > test_helper.rb file that I include in all my spec files: > > > > # replace rspec''s mocks with mocha > > require ''mocha'' > > module Spec > > module Mocks > > remove_method :mock > > remove_method :stub > > remove_method :verify_mocks if method_defined? :verify_mocks > > include Mocha::AutoVerify > > end > > end > > > > Now I have working mock(), stub() and verify_mocks(). Not sure what > > other Mocha stuff I''m missing yet, but I''ll let you know how I get on. > > > > I noticed that Mocha::Standalone also references > > Mocha::SetupAndTeardown, but I didn''t see anything in there that seemed > > relevant to rspec mocking. > > > Hi Dan, > > I''m glad you like Mocha''s mocking dialect. It''s great you''ve got Mocha > working with RSpec. > > Mocha::Standalone was an early attempt at simplifying integration with other > testing frameworks prompted by a request from the RSpec community. Work on > this ground to a halt when RSpec developed their own mocking functionality. > > Mocha::SetupAndTeardown is to do with what RSpec call partial mocks i.e. > where you are mocking a method on a concrete class or object. Looking at > what you''ve done, I suspect you will still be able to setup expectations > like this but (a) they won''t be verified and (b) the concrete class or > object won''t be returned to its original state (Mocha temporarily messes > with the method implementation). > > Let us know if there are any changes we can make that would make the > integration easier.Dan and James, Thank you both for moving on this. I''ve been wanting to figure out an easy way to let people choose their mock framework when they use rspec, but there have been other priorities in rspec and limited resources. What I''d like to see is something that I can build into rspec such that people can either choose to use mocha for an entire project by putting a single declaration in a helper file with no monkey patching (in fact, the structure Dan patched has already changed in rspec''s trunk), or by including a module in a given context/describe block. If you guys can work together to make that happen, I''ll make it a first class citizen of rspec as soon as any relevant changes are released in mocha. Cheers, David> -- > James. > http://blog.floehopper.org > _______________________________________________ > mocha-developer mailing list > mocha-developer at rubyforge.org > http://rubyforge.org/mailman/listinfo/mocha-developer >
On 13/03/07, Dan North <dan at tastapod.com> wrote:> > Yes you''re right - it doesn''t automagically verify, but the verify_mocks > method is in scope and I like to have that explicitly in my spec methods > anyway.Actually I was thinking of the poorly named "verify_stubs" (as opposed to "verify_mocks") and "teardown_stubs" methods in Mocha::SetupAndTeardown. These are to do with the "partial mocking" I mentioned in my previous email. But perhaps you aren''t using that aspect of Mocha. If you do something like this... now = Time.parse(''2006-01-01 00:00:00'') Time.stubs(:now).returns(now) Unless you call the methods in Mocha::SetupAndTeardown, "Time.now" will continue to return the fixed value "now" after the test has finished. -- James. http://blog.floehopper.org
On 3/13/07, Dan North <dan at tastapod.com> wrote:> Yes you''re right - it doesn''t automagically verify, but the verify_mocks > method is in scope and I like to have that explicitly in my spec methods > anyway. > > The big things on my wishlist are: > > 1. Matchers in with(..) like JMock has: > expects(:chew).with(is_a(Chewable), ANYTHING) where is_a(..) is a > [something] that responds to matches?(actual) with true/false, and > ANYTHING is a matcher that always returns true. That way, you could use > rspec''s expectation matcher framework or roll your own matchers. (I''ve > got a bunch I wrote for my own mocking framework - everyone should write > a mocking framework at least twice once :) > > The method matches?(actual) seems fairly universal across these frameworks.rspec''s mocking framework uses matcher.matches?(actual) and use matcher.description to build the failure message. If you use these methods, then rspec users will be able to use rspec''s matchers (which are usable for both mock expectations and state expectations/assertions) within mocha expectations in rspec. In fact, test/unit users would be able to use them as well - they''d just have to get the rspec gem and require ''spec/matchers'' (which doesn''t depend on any other parts of rspec). Hope I''m not being too intrusive here. I''d really love to see the day where rspec need not support its own mocking framework. Making mocha a first class option within rspec is a big first step towards this goal.> > 2. Type-aware mocks that fail with a NoMethodError if the underlying > type doesn''t respond to an invoked method or method_missing (see earlier > thread). > > 3. Something akin to after(another_mock, :method). > > None of these are showstoppers, but 1 is really high on my priorities > and 2 and 3 would make my life happier. I might try to roll something > for 1 if I get the time (read: unlikely!). > > Cheers, > Dan > > James Mead wrote: > > On 12/03/07, Dan North <dan at tastapod.com> wrote: > > > >> I''ve just started using rspec and I have to say it''s very nice. The > >> thing is, I prefer mocha''s mocking dialect. So I thought a simple > >> require ''mocha'' would set me up. > >> > >> Unfortunately, rspec does all its goodness using do/end blocks in > >> anonymous classes, so it wasn''t quite that obvious. > >> > >> Anyway, here is the incantation I ended up using in my equivalent of a > >> test_helper.rb file that I include in all my spec files: > >> > >> # replace rspec''s mocks with mocha > >> require ''mocha'' > >> module Spec > >> module Mocks > >> remove_method :mock > >> remove_method :stub > >> remove_method :verify_mocks if method_defined? :verify_mocks > >> include Mocha::AutoVerify > >> end > >> end > >> > >> Now I have working mock(), stub() and verify_mocks(). Not sure what > >> other Mocha stuff I''m missing yet, but I''ll let you know how I get on. > >> > >> I noticed that Mocha::Standalone also references > >> Mocha::SetupAndTeardown, but I didn''t see anything in there that seemed > >> relevant to rspec mocking. > >> > > > > > > Hi Dan, > > > > I''m glad you like Mocha''s mocking dialect. It''s great you''ve got Mocha > > working with RSpec. > > > > Mocha::Standalone was an early attempt at simplifying integration with other > > testing frameworks prompted by a request from the RSpec community. Work on > > this ground to a halt when RSpec developed their own mocking functionality. > > > > Mocha::SetupAndTeardown is to do with what RSpec call partial mocks i.e. > > where you are mocking a method on a concrete class or object. Looking at > > what you''ve done, I suspect you will still be able to setup expectations > > like this but (a) they won''t be verified and (b) the concrete class or > > object won''t be returned to its original state (Mocha temporarily messes > > with the method implementation). > > > > Let us know if there are any changes we can make that would make the > > integration easier. > > > > _______________________________________________ > mocha-developer mailing list > mocha-developer at rubyforge.org > http://rubyforge.org/mailman/listinfo/mocha-developer >
On 13/03/07, Dan North <dan at tastapod.com> wrote:> > The big things on my wishlist are: > > 1. Matchers in with(..) like JMock has: > expects(:chew).with(is_a(Chewable), ANYTHING) where is_a(..) is a > [something] that responds to matches?(actual) with true/false, and > ANYTHING is a matcher that always returns true. That way, you could use > rspec''s expectation matcher framework or roll your own matchers. (I''ve > got a bunch I wrote for my own mocking framework - everyone should write > a mocking framework at least twice once :) > > The method matches?(actual) seems fairly universal across these > frameworks.Something like this has been on the drawing board for a while. You can currently achieve something similar by using a block on the call to with(), but I admit the syntax is not great. expects(:chew).with { |mouthful1, mouthful2| mouthful1.is_a?(Chewable) } 2. Type-aware mocks that fail with a NoMethodError if the underlying> type doesn''t respond to an invoked method or method_missing (see earlier > thread).3. Something akin to after(another_mock, :method).> > None of these are showstoppers, but 1 is really high on my priorities > and 2 and 3 would make my life happier. I might try to roll something > for 1 if I get the time (read: unlikely!). >Cool. My bandwidth is a bit limited at the moment too, but I''ll see what we can do. Thanks for your constructive suggestions. -- James. http://blog.floehopper.org
I came up with a hacky way of doing named matchers by using lambdas: first_arg_is_chewable = proc {|arg1, arg2| arg1.is_a? Chewable } # ... sheep.expects(:chew).with(&first_arg_is_chewable) which while readable is fugly :) I used it when I wanted to reuse the same with-block. But yes, positional matchers would be much easier on both the eye and the brain! James Mead wrote:> On 13/03/07, Dan North <dan at tastapod.com> wrote: > >> The big things on my wishlist are: >> >> 1. Matchers in with(..) like JMock has: >> expects(:chew).with(is_a(Chewable), ANYTHING) where is_a(..) is a >> [something] that responds to matches?(actual) with true/false, and >> ANYTHING is a matcher that always returns true. That way, you could use >> rspec''s expectation matcher framework or roll your own matchers. (I''ve >> got a bunch I wrote for my own mocking framework - everyone should write >> a mocking framework at least twice once :) >> >> The method matches?(actual) seems fairly universal across these >> frameworks. >> > > > Something like this has been on the drawing board for a while. > > You can currently achieve something similar by using a block on the call to > with(), but I admit the syntax is not great. > > expects(:chew).with { |mouthful1, mouthful2| mouthful1.is_a?(Chewable) } > > 2. Type-aware mocks that fail with a NoMethodError if the underlying > >> type doesn''t respond to an invoked method or method_missing (see earlier >> thread). >> > > > > 3. Something akin to after(another_mock, :method). > >> None of these are showstoppers, but 1 is really high on my priorities >> and 2 and 3 would make my life happier. I might try to roll something >> for 1 if I get the time (read: unlikely!). >> >> > > Cool. My bandwidth is a bit limited at the moment too, but I''ll see what we > can do. > > Thanks for your constructive suggestions. > >
The other thing I should have suggested is - have a look at standalone_acceptance_test.rb and look at the NotATestUnitTestCase class. -- James. http://blog.floehopper.org
Hello Dan & James The code below should provide the feature you are looking for. It allows you to create an expectation like this: obj.expects(:a_method).with(1, Fixnum, Object) obj.a_method(1, 100, :anything) Index: trunk/test/unit/expectation_test.rb ==================================================================--- trunk/test/unit/expectation_test.rb (revision 109) +++ trunk/test/unit/expectation_test.rb (working copy) @@ -30,6 +30,16 @@ assert expectation.match?(:expected_method, 1, 2, 3) end + def test_should_match_calls_to_same_method_with_expected_parameter_values_or _class + expectation = new_expectation.with(1, Fixnum, Object) + assert expectation.match?(:expected_method, 1, 2, 3) + end + + def test_should_match_calls_to_same_method_with_expected_parameter_values_or _class + expectation = new_expectation.with(1, Fixnum, Object) + assert expectation.match?(:expected_method, 1, Fixnum, 3) + end + def test_should_match_calls_to_same_method_with_parameters_constrained_as_ex pected expectation = new_expectation.with() {|x, y, z| x + y == z} assert expectation.match?(:expected_method, 1, 2, 3) Index: trunk/lib/mocha/expectation.rb ==================================================================--- trunk/lib/mocha/expectation.rb (revision 109) +++ trunk/lib/mocha/expectation.rb (working copy) @@ -22,9 +22,6 @@ class InvalidExpectation < Exception; end class AlwaysEqual - def ==(other) - true - end end attr_reader :method_name, :backtrace @@ -43,7 +40,15 @@ end def match?(method_name, *arguments) - (@method_name == method_name) and (@parameter_block ? @parameter_block.call(*arguments) : (@parameters == arguments)) + return false unless @method_name == method_name + return @parameter_block.call(*arguments) unless @parameter_block.nil? + return true if @parameters.is_a? AlwaysEqual + return false unless @parameters.size == arguments.size + @parameters.inject([0, true]) do |result, arg| + result[1] &&= (arguments[result.first].is_a?(Module) ? arg == arguments[result.first] : arg === arguments[result.first]) + result[0] += 1 + result + end.last end # :startdoc: On Mar 13, 2007, at 8:41 AM, Dan North wrote:> I came up with a hacky way of doing named matchers by using lambdas: > > first_arg_is_chewable = proc {|arg1, arg2| arg1.is_a? Chewable } > # ... > sheep.expects(:chew).with(&first_arg_is_chewable) > > which while readable is fugly :) I used it when I wanted to reuse the > same with-block. > > But yes, positional matchers would be much easier on both the eye and > the brain! > > James Mead wrote: >> On 13/03/07, Dan North <dan at tastapod.com> wrote: >> >>> The big things on my wishlist are: >>> >>> 1. Matchers in with(..) like JMock has: >>> expects(:chew).with(is_a(Chewable), ANYTHING) where is_a(..) is a >>> [something] that responds to matches?(actual) with true/false, and >>> ANYTHING is a matcher that always returns true. That way, you >>> could use >>> rspec''s expectation matcher framework or roll your own matchers. >>> (I''ve >>> got a bunch I wrote for my own mocking framework - everyone >>> should write >>> a mocking framework at least twice once :) >>> >>> The method matches?(actual) seems fairly universal across these >>> frameworks. >>> >> >> >> Something like this has been on the drawing board for a while. >> >> You can currently achieve something similar by using a block on >> the call to >> with(), but I admit the syntax is not great. >> >> expects(:chew).with { |mouthful1, mouthful2| mouthful1.is_a? >> (Chewable) } >> >> 2. Type-aware mocks that fail with a NoMethodError if the underlying >> >>> type doesn''t respond to an invoked method or method_missing (see >>> earlier >>> thread). >>> >> >> >> >> 3. Something akin to after(another_mock, :method). >> >>> None of these are showstoppers, but 1 is really high on my >>> priorities >>> and 2 and 3 would make my life happier. I might try to roll >>> something >>> for 1 if I get the time (read: unlikely!). >>> >>> >> >> Cool. My bandwidth is a bit limited at the moment too, but I''ll >> see what we >> can do. >> >> Thanks for your constructive suggestions. >> >> > > _______________________________________________ > mocha-developer mailing list > mocha-developer at rubyforge.org > http://rubyforge.org/mailman/listinfo/mocha-developer
Jay, David, Thanks for all your messages and patches. I''ve just got back from holiday so haven''t had much time to digest them. I am keen to improve the parameter matching in Mocha and the JMock/Hamcrest-style approach is my favourite. I''ll try and get something committed asap. -- James. http://blog.floehopper.org