Mocking behaviour of method with anonymous inner class argument

3,187 views
Skip to first unread message

Graham Crockford

unread,
Oct 6, 2014, 6:43:50 AM10/6/14
to spockfr...@googlegroups.com
I'm playing around with some of our existing Mockito-based Java tests to try and see if we can write them better using Spock.  I'm a little unfamiliar with Groovy, so this could just be a Groovy question, but nevertheless, here goes:

I have the following method under test:

    private void performAction(final T bar, final Foo foo) {
      factory
.getBlob().doWork(new Work() {
       
@Override
       
public void execute(Connection connection) throws SQLException {
         
// does some stuff with bar, foo and connection
       
}
     
});
   
}

I would like to mock out factory.getBlob() so that it responds to doWork(Work) by simply calling Work.execute(...).

The existing Mockito based test looks like this:

@Mock Factory factory;
@Mock Blob blob;
...
when(factory.getBlob()).thenReturn(blob);
doAnswer
(new Answer<Void>() {
 
@Override
 
public Void answer(InvocationOnMock invocation) throws Throwable {
   
((Work)invocation.getArguments()[0]).execute(mock(Connection.class));
   
return null;
 
}
}).when(blob).doWork(any(Work.class));


I tried to write it like this, which would be a very nice way to prove some Spock joy:

Factory factory = Mock()
Blob blob = Mock()
...
factory
.getBlob() >> session
blob
.doWork(_ as Work) >> {w -> w.execute(Mock(Connection))}

Unfortunately, this fails to match, since it seems that doWork is getting an ArrayList with a single entry passed to it, not a Work.  I tried:

Factory factory = Mock()
Blob blob = Mock()
...
factory
.getBlob() >> session
blob
.doWork(_) >> {w -> w[0].execute(Mock(Connection))}

This now matches and executes, but I get an NPE in execute, because bar and foo are not set.  I guess Mockito is doing some cleverness with the scoped finals and the stack which Spock isn't.  How can I make this work?  Furthermore, how is doWork being called with an ArrayList?

Thanks!

pnie...@gmail.com

unread,
Oct 6, 2014, 7:13:10 AM10/6/14
to spockfr...@googlegroups.com
Hi Graham,

On 06 Oct 2014, at 12:43, Graham Crockford <gcroc...@gmail.com> wrote:

Unfortunately, this fails to match, since it seems that doWork is getting an ArrayList with a single entry passed to it, not a Work.

You can either use `w[0]`, or use a typed parameter (`Work w -> …`).

This now matches and executes, but I get an NPE in execute, because bar and foo are not set.

Perhaps you aren’t passing appropriate arguments when you call the method under test?

By the way, you can nest the interactions as follows:

def factory = Mock(Factory) {
  getBlob() >> Mock(Blob) {
    doWork(_) >> { Work w -> w.execute(Mock(Connection)) }
}

If you aren’t interested in how many times the methods get called, consider using `Stub()` instead of `Mock()`.

Cheers,
Peter
signature.asc
Reply all
Reply to author
Forward
0 new messages