dhamini-poornachandra / mockito

Automatically exported from code.google.com/p/mockito
0 stars 0 forks source link

Need autobox support for ArgumentCaptor #99

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
The following code:

    ArgumentCaptor<Integer> capturedCount = new ArgumentCaptor<Integer>();
    verify(mock).someMethod(capturedCount.capture());

will throw an NPE on the verify line if someMethod() takes a primitive value:

    void someMethod(int count);

This is because of Java's autoboxing feature -- ArgumentCaptor.capture() is
currently returning null for all types.

I don't think it's possible to autodetect this case, so I'm not 100% sure
how you'd like to fix this (possibly a parameter to capture() that
specifies the "return" value?).

My current workaround is to create a static method that returns a supplied
value:

    private static <T> T capture(ArgumentCaptor<T> captor, T value) {
        captor.capture();
        return value;
    }

Original issue reported on code.google.com by j...@kikini.com on 25 Jun 2009 at 5:46

GoogleCodeExporter commented 8 years ago
Sorry, forgot to mention that I'm using 1.8-rc2.

Original comment by j...@kikini.com on 25 Jun 2009 at 5:54

GoogleCodeExporter commented 8 years ago
Very well spotted. Thanks a lot for reporting!

Ok, I see 2 options here. Let me know what do you think or generate some more 
options:

1. captor will have methods like captureInt(), captureLong(), captureBoolean(), 
etc.
2. captor will be created without type info. Type info will be added when 
calling
capture:

ArgumentCaptor captor = new ArgumentCaptor();
verify(mock).foo(captor.capture(Integer.class));

Thoughts?

Original comment by szcze...@gmail.com on 26 Jun 2009 at 9:10

GoogleCodeExporter commented 8 years ago
Hmmm, that's a tough one. I think option 1 might be the better choice, though.

With option 1, I unfortunately have to repeat myself on the verify line:

    ArgumentCaptor<Boolean> captor = new ArgumentCaptor<Boolean>();
    verify(mock).someMethod(captor.captureBoolean());
    // assertTrue(captor.getValue());

With option 2, I will still have to repeat myself (with object casts), but I 
also
lose the type safety that generics would give me:

    ArgumentCaptor captor = new ArgumentCaptor();
    verify(mock).someMethod(captor.capture(Boolean.class));
    // assertTrue((Boolean)captor.getValue());

Another option to consider:

    ArgumentCaptor<Integer> captor = new ArgumentCaptor<Integer>(Integer.class);

That's a lot of "Integer" repetition, but it is confined to one line. :) You 
could
potentially provide a factory to help:

    ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);

Original comment by j...@kikini.com on 27 Jun 2009 at 6:56

GoogleCodeExporter commented 8 years ago
Good ideas. I'm thinking in option 2 you still can maintain type safety:

<T> T capture(Class<T> clazz);

>  ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);

Good idea. The only little problem is that java devs are more used to natural 
way of
creating objects: constructors.

Original comment by szcze...@gmail.com on 27 Jun 2009 at 10:19

GoogleCodeExporter commented 8 years ago

Original comment by szcze...@gmail.com on 9 Jul 2009 at 12:53

GoogleCodeExporter commented 8 years ago
This issue was closed by r1566.

Original comment by szcze...@gmail.com on 19 Jul 2009 at 9:03

GoogleCodeExporter commented 8 years ago
Fixed in trunk. This is how you construct ArgumentCaptors since now:

ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);

Original comment by szcze...@gmail.com on 19 Jul 2009 at 9:43