how to expect no method is ever called?

20 views
Skip to first unread message

Alain Ravet

unread,
Jul 8, 2008, 9:10:23 AM7/8/08
to mocha-developer
Hi all,

You cannot write
Factory.expects(/.*/).never
because Object.expects(..) requires a symbol as parameter, that maps a
method name.

How do you map ALL the methods of a given class?
In my case, I need to ensure that a class' (static) methods are never
called.

TIA

Alain

Ken Collins

unread,
Jul 8, 2008, 9:16:19 AM7/8/08
to mocha-d...@googlegroups.com

Alain,

How about:

object.methods.each { |m| object.expects(m).never }

James Mead

unread,
Jul 8, 2008, 9:26:48 AM7/8/08
to mocha-d...@googlegroups.com
2008/7/8 Alain Ravet <alain...@gmail.com>:
I'm pretty sure this is not currently possible.

I have toyed with the idea of MethodMatcher classes like the ParameterMatcher clasess, but there are some problems when it comes to doing this with partial mocks . In the case you describe we would need to redefine all the class methods on Factory that matched your regex so that we could intercept calls to any of them. I'll have a bit more of a think and see what I can come up with.

--
James.
http://blog.floehopper.org

Alain Ravet

unread,
Jul 8, 2008, 9:26:49 AM7/8/08
to mocha-d...@googlegroups.com
Ken,

> How about:
> object.methods.each { |m| object.expects(m).never }

That produces a SystemStackError: stack level too deep
see :
$ irb
irb> require 'mocha'
irb> String.methods.each { |m| String.expects(m).never }
SystemStackError: stack level too deep

Alain

John D. Hume

unread,
Jul 11, 2008, 8:13:18 AM7/11/08
to mocha-d...@googlegroups.com
If you want to ensure the thing goes totally untouched, what about
reassigning the constant for the duration of the test? (You can
suppress the 'already initialized constant' warning by first setting
to $-v to nil. Obviously you'd also want to restore both the constant
and $-v.)

It would read terribly inline, but with a helper method it could be
something like:
it "doesn't touch Foo" do
mocking_constant :Foo => mock do
Bar.new.baz
end
end

(I have you passing in a new value for the constant only because I
don't know what would make sense for you. Obviously you could just
default it so you didn't have to pass in a Hash.)
-hume.

Duncan Beevers

unread,
Jul 11, 2008, 2:09:28 PM7/11/08
to mocha-d...@googlegroups.com
Hmm, interesting. How about this pass at the problem?

require 'rubygems'
require 'test/unit'
require 'mocha'

# insert override_constant implementation here

module FactoryModule
class Factory
end
end

class NoMethodsAtAllTest < Test::Unit::TestCase
def test_no_methods_are_called_on_factory
FactoryModule.override_constant :Factory, mock('Factory') do
FactoryModule::Factory.explode
end
end
end

NoMethodsAtAllTest.new('test_no_methods_are_called_on_factory')

override_constant is a helper i wrote a while back for constants
defined within specific namespaces, I hadn't considered using it to
override full classes, but class names are just constants. Thanks for
the idea Mr. Hume!

Here's the implementation of override_constant
http://www.dweebd.com/ruby/temporarily-modifying-a-constant/

James Mead

unread,
Aug 22, 2008, 10:20:31 AM8/22/08
to mocha-d...@googlegroups.com
I've added the idea of having MethodMatchers as a feature request [1] so it doesn't get forgotten.

Patches always welcome ;-)
--
James.
http://blog.floehopper.org

[1] http://rubyforge.org/tracker/index.php?func=detail&aid=21639&group_id=1917&atid=7480
Reply all
Reply to author
Forward
0 new messages