简体   繁体   中英

Java Futures returning null while using Mockito

class Student{
int age;
String name;
}

class Demo{

public void getStudentList() {
Future<List<Student>> future = client.getAsyncData();
List<Student> response = futures.get(100l, TimeUnit
           .MILLISECONDS);
 }
}


class StudentTest{

  @Test
  public testData(){
  List<Student> students = new ArrayList();
  Client client = ClientFactory.getInstance();
  Future<List<Student>> mockFuture = mock(Future.class);
  when(client.getAsyncData()).thenReturn(mockFuture);
  when(mockFuture.get(10l,TimeUnit.MILLISECONDS)).thenReturn(students);

  Demo demo = mock(Demo.class);
  demo.getStudentList();

}

** I am getting students List object as null ** Client is 3rd party service, it is abstracted

// How should I mock future list in Java, is this the right way ?

try returning list of initialized student object as list and pass anyInt() or anyString() as argument for get() method.

Let me know if below solution works for you, If not please post error logs:

Future<List<Student>> mockFuture = Mockito.mock(Future.class);
when(client.getAsyncData()).thenReturn(mockFuture);
when(mockFuture.get(anyInt(), any())
.thenReturn(asList(new Student(21, "A"), new Student(22, "B")));

or you can try to create an already completed Future> using CompletableFuture.

when(mockFuture.get(anyInt(), any()))
.thenReturn(CompletableFuture.completedFuture(Arrays.asList(new Student(21, "A"), new Student(22, "B"))));

Once you mocked the Future class, you need to stub it to return mock list object as below:

Future future = Mockito.mock(Future.class);
Mockito.when(future.get()).thenReturn(new ArrayList<>());

Then you can verify the future object as:

assertTrue(future.get() instanceof List);
assertTrue(((List) future.get()).isEmpty());

In your case, it would be something like this:

    @Test
    public void testData(){
        Client client = ClientFactory.getInstance(); // make sure client is mock

        // mock future and stub it
        Future mockFuture = mock(Future.class);
        List<Student> students = new ArrayList<>();
        when(mockFuture.get()).thenReturn(students);

        // mock stub the client
        when(client.getAsyncData()).thenReturn(mockFuture);

        // verify
        // . . .
    }

Let me know if below solution works for you or you need any further help/clarifications

//sugeestion: add an access modifier for the member variables
class Student{
int age;
String name;
}

class Demo{

public void getStudentList() {
Future<List<Student>> future = client.getAsyncData();
 }
}


class StudentTest{

  @Test
  public testData(){
/*Since its a Unit test case we must mock the other Object behavior to keep things simple and focused*/
  Client client = Mockito.spy(ClientFactory.getInstance());
  Future<List<Student>> mockFuture = mock(Future.class);
  when(client.getAsyncData()).thenReturn(mockFuture);
}

If you don't need any timeout here (and according to your code you don't), You can omit mocks and return just completedFuture which was added in java8.

  List<Student> students = new ArrayList();
  Client client = ClientFactory.getInstance();
  Future<List<Student>> mockFuture = CompletableFuture.completedFuture(students);
  when(client.getAsyncData()).thenReturn(mockFuture);

You have created Student Object as a part of List implementation with line List students = new ArrayList() but you have not passed values to that object. In your structure you can add students members such as students.add("Rat", "30") which will create an object with values so you can go ahead and test it. It's returning NUll because JUnit test is simply saying "hey, there is nothing for me to test because object in List implementation that you have done is empty"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM