Search code examples
javamockitospy

Spy with mockito a class extending ArrayBlockingQueue


Hello anyone would know how to spy a class that is extending ArrayBlockingQueue? For example I want to spy the following MyBufferQueue class

public class MyBufferQueue extends ArrayBlockingQueue<MyBuffer> {}

Inside of ArrayBlockingQueue class that belongs to java library, there is this method:

public void put(E e) throws InterruptedException {
   Objects.requireNonNull(e);
   final ReentrantLock lock = this.lock;
   lock.lockInterruptibly();
   try {
       while (count == items.length)
       notFull.await();
       enqueue(e);
   } finally {
       lock.unlock();
   }
}

The problem I have is that when I am spying the class MyBufferQueue and during the test when it is accessed the method ArrayBlockingQueue.put(E e), I am getting a NullPointerException in this.lock, when it is supposed that it shouldn't be null as I am creating a new instance of MyBufferQueue in my test, and when creating the new instance the fields inside of ArrayBlockingQueue should be instantiated too as ArrayBlockingQueue is the super class.

This is how would look the test method:

@Test
void testMyBuffer() {
    MyBufferQueue queue = spy(new MyBufferQueue(1));
    doNothing().when(queue).retryAll();
    
    queue.consumeFullQueue();

    verify(queue).retryAll();
}

For spying I am using Mockito version mockito-core:4.7.0 and I am using Java 18.

Thanks in advance.


Solution

  • I've had the same problem recently, and it's caused by how Java 17 and up (possibly earlier, but at least after Java 11) works in combination with Mockito. Instance fields of spied objects remain null.

    The solution is very simple - replace mockito-core with mockito-inline. Same groupId, same version, just a different artifactId.