Hot questions for Using Mockito in asynchronous

Hot questions for Using Mockito in asynchronous

Top 10 Java Open Source / Mockito / asynchronous

Question:

What is the best way to mock asynchronous (@Async) method with mockito? Provided service below:

@Service
@Transactional(readOnly=true)
public class TaskService {
    @Async
    @Transactional(readOnly = false)
    public void createTask(TaskResource taskResource, UUID linkId) {
        // do some heavy task
    }
}

Mockito's verification as below:

@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
public class SomeControllerTest {
    @Autowired
    MockMvc mockMvc;
    @MockBean    
    private TaskService taskService;
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    // other details omitted...

    @Test
    public void shouldVerify() {
        // use mockmvc to fire to some controller which in turn call taskService.createTask
        // .... details omitted
        verify(taskService, times(1)) // taskService is mocked object
            .createTask(any(TaskResource.class), any(UUID.class));
    } 
}

The test method shouldVerify above will always throw:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced argument matcher detected here:

-> at SomeTest.java:77) // details omitted
-> at SomeTest.java:77) // details omitted 

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(anyObject());
    verify(mock).someMethod(contains("foo"))

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.

The exception above won't happend if I remove @Async from the TaskService.createTask method.

Spring Boot version: 1.4.0.RELEASE

Mockito version: 1.10.19


Answer:

There's a bug in Spring Boot that we hope to fix in 1.4.1. The problem is that your mock TaskService is still being called asynchronously which breaks Mockito.

You could work around the problem by creating an interface for TaskService and creating a mock of that. As long as you leave the @Async annotation only on the implementation things will then work.

Something like this:

public interface TaskService {

    void createTask(TaskResource taskResource, UUID linkId);

}

@Service
@Transactional(readOnly=true)
public class AsyncTaskService implements TaskService {

    @Async
    @Transactional(readOnly = false)
    @Override
    public void createTask(TaskResource taskResource, UUID linkId) {
        // do some heavy task
    }

}

Question:

I have implemented an asynchronous method in a Java 1.8 class using Spring Framework (version 5.0.5.RELEASE):

public class ClassToBeTested {
    @Autowired
    private MyComponent myComponent;

    @Async
    public void doStuff(List<MyClass> myObjects) {
        CompletableFuture<MyResponseObject>[] futureList = new CompletableFuture[myObjects.size()];
        int count = 0;

        for (MyClass myObject : myObjects) {
            futureList[count] = myComponent.doOtherStuff(myObject);
            count++;
        }

        // Wait until all doOtherStuff() calls have been completed
        CompletableFuture.allOf(futureList).join();

        ... other stuff ...
    }
}

I'm trying to test the class with JUnit and Mockito. I have set it up as follows, with an aim of mocking the doStuff() method's call to the component:

@MockBean
private MyComponent myComponentAsAMock;

@InjectMocks
@Autowired
private ClassToBeTested classToBeTested;

@Test
public void myTest() throws Exception {
    // Create object to return when myComponent.doOtherStuff() is called.
    CompletableFuture<MyResponseObject> completableFuture = new CompletableFuture<MyResponseObject>();
    ... populate an instance of MyResponseObject ...
    completableFuture.complete(myResponseObject);

    // Return object when myComponent.doOtherStuff() is called.
    Mockito.when(
        myComponentAsAMock.doOtherStuff(ArgumentMatchers.any(MyClass.class)))
        .thenReturn(completableFuture);

    // Test.
    List<MyClass> myObjects = new ArrayList<MyClass>();
    MyClass myObject = new MyClass();
    myobjects.add(myObject);
    classToBeTested.doStuff(myObjects);
}

Whilst the unit test seems to be successful when I run it individually in Eclipse, but doing a Maven build of the whole project I notice NullPointerExceptions are being thrown:

[ThreadExecutor2] .a.i.SimpleAsyncUncaughtExceptionHandler : Unexpected error occurred invoking async method 'public void package.ClassToBeTested.doStuff(java.util.List)'.

java.lang.NullPointerException: null
at java.util.concurrent.CompletableFuture.andTree(CompletableFuture.java:1306) ~[na:1.8.0_131]
at java.util.concurrent.CompletableFuture.allOf(CompletableFuture.java:2225) ~[na:1.8.0_131]
at package.ClassToBeTested.doStuff(ClassToBeTested.java:75) ~[classes/:na]

The error is being raised on this line of ClassToBeTested.java:

CompletableFuture.allOf(completedFutureList).join();

It looks like the exception message is being displayed in the Maven build output after the test has finished (there are other tests being run whose output occur before the error message is being displayed), so I'm guessing it's something to do with the fact that the call to doStuff() is asynchronous.

Any assistance would be appreciated.


Answer:

The solution was to add in a Mockito verification step with a timeout and a check to ensure that the mocked component's method had been called the appropriate number of times:

    Mockito.verify(myComponentAsAMock, Mockito.timeout(1000).times(1)).doOtherStuff(ArgumentMatchers.any(MyClass.class));

Question:

I am writing an integration test against some code that asynchronously creates a record when a different value is updated in the database. I would like to check the state of the system after the record is created, verifying that it was created as expected. The test therefore needs to wait until the record is created.

I can use Mockito to create a spy for the function that creates the record. Mockito even has the option to wait for the method to be called via Mockito.timeout, giving up if a certain amount of time has elapsed without the method being called:

// Use or create/wire in spy. In my case, this is set up with @SpyBean from spring-boot-test.
RecordCreationService recordCreationServiceSpy = ...;

testClass.update(someValue);

Mockito.verify(recordCreationServiceSpy, Mockito.timeout(10_000)).createRecord(ArgumentMatchers.any());

However, this merely waits for the call to have started, not for it to have been completed. Thus, this enters a race condition where the verification can finish before the desired call completes.

How can I cleanly and simply wait for the completion of a process before verifying in JUnit with Mockito?


Answer:

This functionality doesn't directly exist in Mockito, as there is currently an open issue to add this functionality to Mockito (Mockito issue #1089).

The solution I am currently using is to write a custom answer for the spied method that waits for the call to be completed before returning. I then verify the result normally afterward.

@SpyBean
private RecordCreationService recordCreationServiceSpy;

@Test(timeout = 10_000)
public void recordShouldBeCreatedWhenDataIsUpdated() {
    // Set up test here

    updateValueAndWait(value);

    assertEquals(1, recordRepository.findAll().size());
    // Perform any additional verifications
}

private void updateValueAndWait(String value) {
    CountDownLatch latch = new CountDownLatch(1);
    Mockito.doAnswer(invocation -> {
        Object result = invocation.callRealMethod();
        latch.countDown();
        return result;
    }).when(recordCreationServiceSpy).insertRecord(any());

    testClass.update(value);

    try {
        latch.await();
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

Question:

The following method calls the method serveThis() of a service synchronously and the method serveThat() in a separate thread i.e. asynchronously:

public void doSomething() {
    service.serveThis();
    new Thread(() -> service.serveThat()).start();
}

I want to verify in a unit test that service.serveThat() will be executed asynchronously as according to the specification it must not be executed synchronously. So, I want to prevent that later on someone just removes starting a new thread like this:

public void doSomething() {
    service.serveThis();
    // This synchronous execution must cause the test to fail
    service.serveThat();
}

Answer:

It's possible to get Thread.currentThread() anywhere in the code, so you can write something like this and make asserts based on it (you can achieve this with Mockito in a different way if you don't have YourInterface):

public class ThreadChecker implements YourInterface {

    volatile Thread serveThisThread;
    volatile Thread serveThatThread;

    public void serveThis() {
        serveThisThread = Thread.currentThread();
    }

    public void serveThat() {
        serveThatThread = Thread.currentThread();
    }
}

A unit test can be something like this, but additional asserts might be needed based on the use case:

ThreadChecker mockService = new ThreadChecker(); 

@Test
public void serveThatWillBeExecutedAsynchronously() throws Exception {
    doSomething();
    TestCase.assertFalse(mockService.serveThatThread == mockService.serveThisThread);
}

Question:

I have following classes:

public class ForTest {
    public void methodToTest(Thread thread){
        thread.start();
    }
}
class MyThread extends Thread{
    FooClass fooClass;
    public MyThread(FooClass fooClass){
        this.fooClass = fooClass;
    }
    @Override
    public void run() {
        fooClass.bar();
    }
}
class FooClass{
    public void bar(){}
}

I want to test method methodToTest. I want to pass instance of MyThread as argument of mentioned method.

As a result I want to verify that method bar was invoked.

Can you help me to write it using Mockito or Powermock?


Answer:

Couple of things to consider:

  1. Because you are using external thread, some kindof waiting/blocking is necessary.
  2. If the thread code is more complicated and because we need to wait for the thread to finish its execution generally speaking (not your case), it will be necessary to use timeout functionality.
  3. You don't have to use mocks at all, e.g. the FooClass.bar() method can set/modify a field which will be then checked for a changed value.

    @Test
    public void testSomeMethod() throws InterruptedException {
        FooClass fooClassMock = Mockito.mock(FooClass.class);
        Thread thread = new MyThread(fooClassMock);
    
        new ForTest().methodToTest(thread);
    
        thread.join();
    
        Mockito.verify(fooClassMock).bar();
    }