Home > Back-end >  How to spy on an object that is instantiated with Callable<T> arg and implements Closeable wit
How to spy on an object that is instantiated with Callable<T> arg and implements Closeable wit

Time:05-28

I am trying to figure out how to skip a non-static void method call in a unit test by using Mockito and spying on the object.

The class in question is:

public class CallableExecutor<T> implements Closeable {

  public CallableExecutor( String s, Callable<T> c ) {
     this.s = s;
     this.c = c;
  }

  public void methodWeAreTryingToSkip( String string ) {
     // some logic
  }

}

The method I am trying to unit test is:

public String myMethodThatIsBeingUnitTested( args ) {
   AtomicReference<String> id = new AtomicReference<>();
   try ( CallableExecutor<String> executor = new CallableExecutor<>(
      someString, () -> { id.set( someMethodCall ) );
      return id.get();
    } ) ) {
      executor.methodWeAreTryingToSkip( string );
    }
    catch ( Exception e ) {
      // exception handling
    }
}

In my unit test, I have tried the code outlined below but both end up throwing Mockito errors prior to "doNothing()" line (detailed errors at the bottom):

CallableExecutor<String> mockExecutor = spy( new CallableExecutor<>( any(), any() ) );
doNothing().when( mockExecutor ).methodWeAreTryingToSkip( anyString() );
Callable callable = mock( Callable.class );
CallableExecutor<String> mockExecutor = spy( new CallableExecutor<>( anyString(), eq( callable ) ) );
doNothing().when( mockExecutor ).methodWeAreTryingToSkip( anyString() );

Errors:

Misplaced or misused argument matcher detected here
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

Any help or advice would be appreciated!

CodePudding user response:

You wrote

spy( new CallableExecutor<>( any(), any() ) );

You can't do this. You need to make an actual CallableExecutor object before you can spy it. And that means passing actual values into its constructor, not passing the output of matcher methods.

The matcher methods work by manipulating an internal structure that Mockito uses to store stubbing and verification information. That's why you can only use them during stubbing or verification.

Pass actual non-matcher arguments to the CallableExecutor constructor.

  • Related