Lenny Marks
2011-Aug-22 21:50 UTC
[rspec-users] [JRuby] simulating a java exception in a spec
JRuby 1.6.2 rspec-core (2.6.4) rspec-expectations (2.6.0) rspec-mocks (2.6.0) rspec-rails (2.6.1) I''m sure this has more to do with the way JRuby wraps Java exceptions but I figured I''d post here in case anyone here has any insight or pointers. In the context of writing a spec for a model like thing that wraps legacy Java code, I found myself attempting to stub a method on a Java Exception rescued in the implementation. eg. describe ''#valid?'' do .... it ''adds validation exceptions raised by service to #errors'' do ve = ValidationException #a java exception ve.stub(:localized_message).and_return(''a bunch of errors'') service.stub(:validateTaskForSave).and_raise(ve) subject.valid? subject.errors.should == [''a bunch of errors''] end the above example fails because the :localize_message stub is ignored and instead the real implementation receives the message. I know this typically screams typo but not in this case. Here is a more boiled down version: specify ''rescued exception message should be "bar" because I stubbed it'' do begin e = Java::java.lang.NullPointerException.new(''foo'') e.stub(:message).and_return(''bar'') raise e rescue Java::java.lang.NullPointerException => e e.message.should == ''bar'' end end Failure/Error: e.message.should == ''bar'' expected: "bar" got: "foo" (using ==) That seemed odd to me but maybe moot anyway since in reality I would be need to rescue a NativeException masquerading as my target exception. e.g. This code def valid? begin service.validateTaskForSave(task) rescue ValidationException => e puts "rescued exception: #{e.class.name}" ..... prints "rescued exception: NativeException" when hit through the console. So how would one simulate a NativeException if needed (i.e. you want to stub methods on it)? -lenny
Sidu Ponnappa
2011-Aug-23 17:29 UTC
[rspec-users] [JRuby] simulating a java exception in a spec
it ''adds validation exceptions raised by service to #errors'' do ve = ValidationException #a java exception ve.stub(:localized_message).and_return(''a bunch of errors'') .... Just clarifying, but did you mean ve = ValidationException.new I tried replicating your spec but with java.lang.RuntimeException instead of ValidationException and I got exception class/object expected because raise expects an instance of the exception, not the exception class. Am I missing something? Best, Sidu. http://c42.in http://blog.sidu.in On 23 August 2011 03:20, Lenny Marks <lenny at aps.org> wrote:> service.stub(:validateTaskForSave).and_raise(ve)
Lenny Marks
2011-Aug-23 18:27 UTC
[rspec-users] [JRuby] simulating a java exception in a spec
> > On Aug 22, 2011, at 5:50 PM, Lenny Marks wrote: > >> JRuby 1.6.2 >> rspec-core (2.6.4) >> rspec-expectations (2.6.0) >> rspec-mocks (2.6.0) >> rspec-rails (2.6.1) >> >> I''m sure this has more to do with the way JRuby wraps Java exceptions but I figured I''d post here in case anyone here has any insight or pointers. In the context of writing a spec for a model like thing that wraps legacy Java code, I found myself attempting to stub a method on a Java Exception rescued in the implementation. >> >> eg. >> >> describe ''#valid?'' do >> .... >> it ''adds validation exceptions raised by service to #errors'' do >> ve = ValidationException #a java exception >> ve.stub(:localized_message).and_return(''a bunch of errors'') >> >> service.stub(:validateTaskForSave).and_raise(ve) >> >> subject.valid? >> >> subject.errors.should == [''a bunch of errors''] >> end> it ''adds validation exceptions raised by service to #errors'' do > ve = ValidationException #a java exception > ve.stub(:localized_message).and_return(''a bunch of errors'') > .... > > > Just clarifying, but did you mean > ve = ValidationException.new > > > I tried replicating your spec but with java.lang.RuntimeException > instead of ValidationException and I got > exception class/object expected > > because raise expects an instance of the exception, not the exception > class. Am I missing something? > > Best, > Sidu. > http://c42.in > http://blog.sidu.inYou have to raise an exception instance, not the class of the exception as is typical with Ruby exceptions. Check out the "boiled down" example below to reproduce.>> >> the above example fails because the :localize_message stub is ignored and instead the real implementation receives the message. I know this typically screams typo but not in this case. Here is a more boiled down version: >> >> specify ''rescued exception message should be "bar" because I stubbed it'' do >> begin >> e = Java::java.lang.NullPointerException.new(''foo'') >> e.stub(:message).and_return(''bar'') >> raise e >> rescue Java::java.lang.NullPointerException => e >> e.message.should == ''bar'' >> end >> end >> >> Failure/Error: e.message.should == ''bar'' >> expected: "bar" >> got: "foo" (using ==) >> >> That seemed odd to me but maybe moot anyway since in reality I would be need to rescue a NativeException masquerading as my target exception. >> >> e.g. This code >> >> def valid? >> begin >> service.validateTaskForSave(task) >> rescue ValidationException => e >> puts "rescued exception: #{e.class.name}" >> ..... >> >> prints "rescued exception: NativeException" when hit through the console.The more I think about this, the more I wish it was different(more explicit) in JRuby. IMO, the above is very unintuitive (i.e. if I rescue a specific exception class then I would expect the exception instance to be an instance of that class). Any attempt to reference a custom method on a rescued java exception results in "undefined method". rescue MyJavaException => e # e.some_method "undefined method" e.cause.some_method # need to unwrap end AFAICT, the JRuby wiki makes no mention of this behavior ( https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby ). Of course that''s more suited for the JRuby mailing list, but if it is just a matter of filling in the docs then there should still be an easy way to simulate such an exception with #and_raise such that custom methods on the exception can be stubbed. No?? -lenny>> >> So how would one simulate a NativeException if needed (i.e. you want to stub methods on it)? >> >> -lenny >> >> >> >> >> >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110823/9e98e0ad/attachment.html>
Sidu Ponnappa
2011-Aug-23 18:43 UTC
[rspec-users] [JRuby] simulating a java exception in a spec
Please ignore my previous question - I just realised you''re doing Java::java.lang.NullPointerException.new in your second example. I''m seeing the same behaviour and can''t think of any way around it off the top of my head. You could try redefining Java::JavaLang::NullPointerException to be a Ruby RuntimeError within the scope of your spec but I''m not sure how this will work (if at all) when Java::JavaLang::NullPointerException is raised from native code. Best, Sidu. http://c42.in On 23 August 2011 22:59, Sidu Ponnappa <ckponnappa at gmail.com> wrote:> it ''adds validation exceptions raised by service to #errors'' do > ? ? ve = ValidationException #a java exception > ? ? ve.stub(:localized_message).and_return(''a bunch of errors'') > ? ?.... > > > Just clarifying, but did you mean > ? ?ve = ValidationException.new > > > I tried replicating your spec but with java.lang.RuntimeException > instead of ValidationException and I got > ? exception class/object expected > > because raise expects an instance of the exception, not the exception > class. Am I missing something? > > Best, > Sidu. > http://c42.in > http://blog.sidu.in > > > > On 23 August 2011 03:20, Lenny Marks <lenny at aps.org> wrote: >> service.stub(:validateTaskForSave).and_raise(ve) >