Amit
Amit

Reputation: 495

junit : get method of CompletableFuture<ExecutionResult> never return

In my Spring boot application, I have below two methods, I am writing JUnit for method1 and mocking method processQuery(). but I don't know why when the control reaches to result.get() , It got stuck, and not moving further.

Method 1:
public class Entry(){
public string method1(){
   --some process and then calling method 2
 CompletableFuture<ExecutionResult> result = 
 risk.processQuery(graphQLRequest, context);
 **result.get();** **--Control got stuck here** 
 system.out.println("control not reaching here ");
 }
}

  **TestClass ::**

public class testMain(){
  @InjectMock
  Entry entry;
  @Mock
  Risk risk;

 @Before
    public void setup() {
    entry= new Entry();
    MockitoAnnotations.initMocks(this);
   }

 @Test
   public void testMethod1(){
     CompletableFuture<ExecutionResult> result = new 
     CompletableFuture<ExecutionResult>();


Mockito.doReturn(result).when(risk).processQuery(Mockitt.anyString(),Mockito.any());

entry.method1();
}

Kinde helps me with the above issue.

Upvotes: 0

Views: 3937

Answers (1)

Didier L
Didier L

Reputation: 20598

You are mocking risk.processQuery() with an uncompleted CompletableFuture

CompletableFuture<ExecutionResult> result = new CompletableFuture<ExecutionResult>();
Mockito.doReturn(result).when(risk).processQuery(Mockitt.anyString(),Mockito.any());

When you call get() on a CompletableFuture, it waits until it is completed with a value or an exception. Here you future is never completed, so it waits indefinitely.

You have three solutions here:

  • define your mock such that it returns an already completed future:

    CompletableFuture<ExecutionResult> result = CompletableFuture.completedFuture(someResult);
    
  • make the test call entry.method1() in a separate thread (e.g. with CompletableFuture.supplyAsync()) and then complete the result with result.complete(someResult) in the test;

  • refactor your code such that method1() becomes asynchronous as well, something like:

    public CompletableFuture<String> method1(){
        --some process and then calling method 2
        CompletableFuture<ExecutionResult> result = 
        risk.processQuery(graphQLRequest, context);
        return result.thenApply(result -> result.toString());
    }
    

    then adapt your test to mimic an asynchronous response:

    @Test
    public void testMethod1(){
        CompletableFuture<ExecutionResult> result = new CompletableFuture<ExecutionResult>();
        Mockito.doReturn(result).when(risk).processQuery(Mockitt.anyString(),Mockito.any());
    
        CompletableFuture<String> method1Result = entry.method1();
        result.complete(someResult);
        assertEquals("some String", method1Result.join());
    }
    

Upvotes: 2

Related Questions