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 >