Issue
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()
}
Solution
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 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 overridden 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
.
Answered By - Ricardo Petronilho
Answer Checked By - Senaida (JavaFixing Volunteer)