Home > Enterprise >  How to compare two lists in stream
How to compare two lists in stream

Time:10-01

I want to compare (assert equals) for training purposes two lists in stream. So every id from sampleUsers() with every id from body of response entity should be compared. Should I create another stream? If yes then how to use it?

@Test
  void findAllUsers() {
    when(userService.findAll()).thenReturn(sampleUsers());
    ResponseEntity<List<UserDto>> responseEntity = userController.findAll();

    //first assert
    assertEquals(responseEntity.getStatusCode().value(), 200);

    //second assert
    assertEquals(responseEntity.getBody().size(), sampleUsers().size());

    //third assert
    responseEntity.getBody().stream()
          .filter(user -> user.getId() != null)
          .filter(user -> user.getUsername() != null)
          //TODO check for each user if: 
          //     user.getId is equal to id from sampleUsers() list
          //     something like: assert equals user.getId(), sampleUsers.get(0).getId()
    }

CodePudding user response:

One way is to assert each element of the stream separately which can be done with the help of following code. You can write a function for asserting streams.

static void assertStreamEquals(Stream<User> s1, Stream<User> s2) {
    Iterator<Student> iter1 = s1.iterator(), iter2 = s2.iterator();
    while(iter1.hasNext() && iter2.hasNext())
        assertEquals(iter1.next().id, iter2.next().id);
    assert !iter1.hasNext() && !iter2.hasNext();
}

and call it by passing your two streams.

@Test
void findAllUsers() {
    when(userService.findAll()).thenReturn(sampleUsers());
    ResponseEntity<List<UserDto>> responseEntity = userController.findAll();

    //first assert
    assertEquals(responseEntity.getStatusCode().value(), 200);

    //second assert
    assertEquals(responseEntity.getBody().size(), sampleUsers().size());

    //third assert
    assertStreamEquals(responseEntity.getBody(),sampleUsers);

(Assuming User is the class name for users)

CodePudding user response:

There are many ways to do that assertion. You could override equals() in UserDto class.

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || this.getClass() != o.getClass()) return false;
    UserDto userDto = (UserDto) o;
    return this.id.equals(userDto.id);
}

And a implement a Comparator for UserDto class. This is going to be used to sort both lists.

public class UserDtoComparatorById implements Comparator<UserDto> {
    @Override
    public int compare(UserDto o1, UserDto o2) {
        return o1.getId().compareTo(o2.getId());
    }
}

Finally.

@Test
void findAllUsers() {
    when(userService.findAll()).thenReturn(sampleUsers());
    ResponseEntity<List<UserDto>> responseEntity = userController.findAll();

    //first assert
    assertEquals(responseEntity.getStatusCode().value(), 200);

    //second assert (this is optional)
    assertEquals(responseEntity.getBody().size(), sampleUsers().size());
   
    // to prevent false negatives, in case both lists have same objects
    // but different orders 
    Comparator<UserDto> comparator = new UserDtoComparatorById();
    sampleUsers.sort(comparator);
    responseEntity.getBody().sort(comparator);

    //third assert
    assertEquals(responseEntity.getBody(), sampleUsers);

    //same assertion but using streams
    AtomicInteger i = new AtomicInteger(0);
    assertEquals(
        list1.stream()
             .filter(user -> user.equals(list2.get(i.getAndIncrement())))
             // or: filter(user -> user.getId().equals(list2.get(i.getAndIncrement()).getId()))
             .count(), 
        list1.size()
    );
}

The third assert will work because both lists are sorted and assertEquals() will invoke UserDto.equals() for each element in the same position. As UserDto.equals() is overriten to check only UserDto.id, it will check the id instead of the Object pointer (address in memory), therefore returning true.

Note that in the second alternative you can not use int i because variables inside lambda functions need to be final. A simple workaround is using AtomicInteger.

  • Related