Forum: RSpec [JRuby] simulating a java exception in a spec

54568ee7ba0c78a836e84c8756a3d681?d=identicon&s=25 Lenny Marks (Guest)
on 2011-08-22 23:56
(Received via mailing list)
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
7bb0d7e74198c735783b8a65cd14989c?d=identicon&s=25 Sidu Ponnappa (kaiwren)
on 2011-08-23 19:36
(Received via mailing list)
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
7bb0d7e74198c735783b8a65cd14989c?d=identicon&s=25 Sidu Ponnappa (kaiwren)
on 2011-08-23 21:13
(Received via mailing list)
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
54568ee7ba0c78a836e84c8756a3d681?d=identicon&s=25 Lenny Marks (Guest)
on 2011-08-23 22:25
(Received via mailing list)
>>
>>      subject.valid?
>>
>>      subject.errors.should == ['a bunch of errors']
>> end

> 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

You 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.

>>      end
>> 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
This topic is locked and can not be replied to.