Hey all,
I have a question with using mocha in my tests.
In the same test file, I have two tests,
<code>
def test_a
klass.any_instance.stubs(:method_name).returns("something")
klass.new.method_name
...
end
def test_b
...
klass.new.method_name
...
end
</code>
where klass is some class
when the tests run, test _a passes, but test_b had an error like this:
test_b
NoMethodError: undefined method `method_name'' for
#<klass:0xb6fb1934>
I put a
<code>
puts ''unstub called''
</code>
in unstub of any_instance_method.rb and it got called wen running test_a
Any idea what the problem it could be?
Thanks,
Yi
Every test case would be run separately in unit test system, which means
test_a does not have any relationship with test_b and of coz this statement
in test_a
klass.any_instance.stubs(:method_name).returns("something")
will not influence any code in method test_b.
I think if you move that statement above to the method setup it will works
for you, since this method would be invoked before each test case starting.
On 3/31/07, Yi Wen <hayafirst at gmail.com> wrote:>
> Hey all,
>
> I have a question with using mocha in my tests.
>
> In the same test file, I have two tests,
>
> <code>
> def test_a
> klass.any_instance.stubs(:method_name).returns("something")
> klass.new.method_name
> ...
> end
>
> def test_b
> ...
> klass.new.method_name
> ...
> end
> </code>
>
> where klass is some class
>
> when the tests run, test _a passes, but test_b had an error like this:
>
> test_b
> NoMethodError: undefined method `method_name'' for
#<klass:0xb6fb1934>
>
> I put a
> <code>
> puts ''unstub called''
> </code>
> in unstub of any_instance_method.rb and it got called wen running test_a
>
> Any idea what the problem it could be?
>
> Thanks,
>
> Yi
> _______________________________________________
> mocha-developer mailing list
> mocha-developer at rubyforge.org
> http://rubyforge.org/mailman/listinfo/mocha-developer
>
sorry I mis-presented my case. 1. method_name is an instance method of klass 2. I do NOT want to mock this method in test_b So I guess there is something missing in unstub chain upon exiting test_a or I need to do some teardown myself? Thanks Yi On 3/30/07, Matt Chen <chen.mingquan at gmail.com>> Every test case would be run separately in unit test system, which means > test_a does not have any relationship with test_b and of coz this > statement > in test_a > > klass.any_instance.stubs(:method_name).returns("something") > > will not influence any code in method test_b. > > I think if you move that statement above to the method setup it will works > for you, since this method would be invoked before each test case > starting. > > > On 3/31/07, Yi Wen <hayafirst at gmail.com> wrote: > > > > Hey all, > > > > I have a question with using mocha in my tests. > > > > In the same test file, I have two tests, > > > > <code> > > def test_a > > klass.any_instance.stubs(:method_name).returns("something") > > klass.new.method_name > > ... > > end > > > > def test_b > > ... > > klass.new.method_name > > ... > > end > > </code> > > > > where klass is some class > > > > when the tests run, test _a passes, but test_b had an error like this: > > > > test_b > > NoMethodError: undefined method `method_name'' for #<klass:0xb6fb1934> > > > > I put a > > <code> > > puts ''unstub called'' > > </code> > > in unstub of any_instance_method.rb and it got called wen running test_a > > > > Any idea what the problem it could be? > > > > Thanks, > > > > Yi > > _______________________________________________ > > mocha-developer mailing list > > mocha-developer at rubyforge.org > > http://rubyforge.org/mailman/listinfo/mocha-developer > > > _______________________________________________ > mocha-developer mailing list > mocha-developer at rubyforge.org > http://rubyforge.org/mailman/listinfo/mocha-developer >
I''ve just tried to recreate your problem...
require ''test/unit''
require ''rubygems''
require ''mocha''
class AnyInstanceTest < Test::Unit::TestCase
class Klass
def method_name
"original"
end
end
def test_a
Klass.any_instance.stubs(:method_name).returns("something")
assert_equal "something", Klass.new.method_name
end
def test_b
assert_equal "original", Klass.new.method_name
end
end
...but both tests pass. So I don''t understand why you are having a
problem.
Please send us all the code for the simplest self-contained test case which
illustrates your problem?
What version of Mocha are you using? And are you using it as a gem or as
Rails plugin?
--
James.
http://blog.floehopper.org
I use it as a rails plugin and I am running on 0.30
I put this a_test.rb under RAILS_PROJ_ROOT/test/unit
If running test_a and test_b separately, they work fine, but if running the
whole test suite, it gave me this error:
output "called" is a string I puts in unstub of AnyInstanceMethod
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.7.2
/lib/rake/rake_test_loader
Started
"called"
.E
Finished in 0.011905 seconds.
1) Error:
test_b(ATest):
NoMethodError: undefined method `method_name'' for #<A:0xb6fa0ad0>
/home/ywen/projects/my_proj/test/unit/a_test.rb:6:in `send''
/home/ywen/projects/my_proj/test/unit/a_test.rb:6:in `initialize''
/home/ywen/projects/my_proj/test/unit/a_test.rb:21:in `new''
/home/ywen/projects/my_proj/test/unit/a_test.rb:21:in `test_b''
/home/ywen/projects/my_proj/config/../vendor/plugins/mocha/lib/mocha/test_case_adapter.rb:19:in
`__send_
_''
/home/ywen/projects/my_proj/config/../vendor/plugins/mocha/lib/mocha/test_case_adapter.rb:19:in
`run''
Thanks!
Yi
--------------------------------------------------------------------------------
a_test.rb
require File.dirname(__FILE__) + ''/../test_helper''
class A
attr_reader :b
def initialize
@b = send(''method_name'')
end
private
def method_name
"Original"
end
end
class ATest < Test::Unit::TestCase
def test_a
A.any_instance.stubs(:method_name).returns("stubs")
assert_equal "stubs", A.new.b
end
def test_b
assert_equal "Original", A.new.b
end
end
On 3/30/07, James Mead <jamesmead44 at gmail.com>
wrote:>
> I''ve just tried to recreate your problem...
>
> require ''test/unit''
> require ''rubygems''
> require ''mocha''
>
> class AnyInstanceTest < Test::Unit::TestCase
>
> class Klass
> def method_name
> "original"
> end
> end
>
> def test_a
> Klass.any_instance.stubs(:method_name).returns("something")
> assert_equal "something", Klass.new.method_name
> end
>
> def test_b
> assert_equal "original", Klass.new.method_name
> end
>
> end
>
> ...but both tests pass. So I don''t understand why you are having a
> problem.
>
> Please send us all the code for the simplest self-contained test case
> which
> illustrates your problem?
>
> What version of Mocha are you using? And are you using it as a gem or as
> Rails plugin?
>
> --
> James.
> http://blog.floehopper.org
> _______________________________________________
> mocha-developer mailing list
> mocha-developer at rubyforge.org
> http://rubyforge.org/mailman/listinfo/mocha-developer
>
It looks like the critical aspect of your failing test is the fact that you are stubbing a private method. Originally Mocha did not allow stubbing of private methods. Somehow accidentally it became allowed. Stubbing private methods isn''t a good idea, because it couples the test to the internals of the class. There seems to be a bug with stubbing a private method. I''ll look into it, but in the meantime you can fix your test if you are able to make the stubbed method public. Thanks. -- James. http://blog.floehopper.org
Thanks James, I also looked into the Mocha code. It seems in AnyInstance
class, restore_original_method uses "method_defined?" and this method
matches only public and protected methods in the module/included classes,
etc. (And method_defined? is used in many other cases as well). I think
that''s why the original private method_name was not restored.
<code>
stubbee.class_eval "alias_method :#{method}, :#{hidden_method};
remove_method :#{hidden_method}" if stubbee.method_defined?(hidden_method)
</code>
I agree with you that stubbing a private method is not a good idea in
general. So I agree with you that what need to be done is to disallow
mocking private methods explicitly. From what I can see in a very quick
glance, "stubs" method is not guarded with any checking... Anyway,
just
trying to be helpful.
And thanks again, your correspondence helped a lot.
Yi
On 4/1/07, James Mead <jamesmead44 at gmail.com>
wrote:>
> It looks like the critical aspect of your failing test is the fact that
> you
> are stubbing a private method.
>
> Originally Mocha did not allow stubbing of private methods. Somehow
> accidentally it became allowed. Stubbing private methods isn''t a
good
> idea,
> because it couples the test to the internals of the class.
>
> There seems to be a bug with stubbing a private method. I''ll look
into it,
> but in the meantime you can fix your test if you are able to make the
> stubbed method public.
>
> Thanks.
> --
> James.
> http://blog.floehopper.org
> _______________________________________________
> mocha-developer mailing list
> mocha-developer at rubyforge.org
> http://rubyforge.org/mailman/listinfo/mocha-developer
>