I have a custom query in the repository. And the service that calls this method from the repository.
I want to write a unit test. What should I test for a repository or a service?
Or should I do 2 absolutely identical tests?
CodePudding user response:
You should unit test everything. Test happy-paths sad-paths. The more you test the better your results will be. For repo tests it should be enough to test 1 happy and 1 sad (either you receive the data or you don't) Service tests require more time, say you have a few if-conditions then you would want to test those specific cases as well.
As an example:
@DataJpaTest
class RoleRepoTest {
@Autowired
private RoleRepo roleRepo;
@PersistenceContext
private EntityManager entityManager;
@Test
void itShouldfindRoleByName() {
// given
Role role = new Role(null, "administrator");
roleRepo.save(role);
flushAndClear();
// when
Role roleExpected = roleRepo.findByName("administrator");
// then
assertThat(roleExpected.getName()).isEqualTo(role.getName());
}
@Test
void itShouldNotfindRoleByName() {
// when
Role expectedRole = roleRepo.findByName("name");
assertThat(expectedRole).isNull();
}
private void flushAndClear() {
entityManager.flush();
entityManager.clear();
}
}
Make sure to always flush & clear. This will avoid your tests from failing when running all at once. It ensures that each test is run in a clean and isolated environment. Without flushing and clearing the database, tests may be affected by data that was created or modified during previous tests.
For Service tests I've got the following example:
@Test
void deleteUser_givenUser_whenTryingToDeleteSameUser_thenUserDeleted() {
// given
given(securityContext.getAuthentication().getPrincipal()).willReturn(userDetails);
given(userDetails.getUsername()).willReturn(user.getUsername());
given(userRepo.findByUsername(user.getUsername())).willReturn(user);
userIsStudent();
String username = user.getUsername();
// when
authService.deleteUser(new DeleteAccountDto(username));
// then
verify(userRepo).deactivateUser(username);
}
@Test
void deleteUser_givenLoggedInUserNotAdmin_whenTryingToDeleteUserWithOtherUsername_ThrowError() {
// given
String username = studentUser.getUsername();
// when then
assertThatThrownBy(() -> authService.deleteUser(new DeleteAccountDto(username)))
.isInstanceOf(AccountException.class)
.hasMessage("De gebruikersnaam is niet gevonden.");
verify(userRepo, never()).deactivateUser(username);
}
@Test
void deleteUser_givenLoggedInUserIsAdmin_whenTryingToDeleteExistingUser_ThenUserIsDeleted() {
given(securityContext.getAuthentication().getPrincipal()).willReturn(userDetails);
given(userDetails.getUsername()).willReturn(user.getUsername());
userIsAdmin();
// given
given(userRepo.findByUsername(studentUser.getUsername())).willReturn(studentUser);
String username = studentUser.getUsername();
// when
authService.deleteUser(new DeleteAccountDto(username));
// then
verify(userRepo).deactivateUser(username);
}
@Test
void deleteUser_givenLoggedInUserIsAdmin_WhenTryingToDeleteLoggedInUser_ThenThrowError() {
given(securityContext.getAuthentication().getPrincipal()).willReturn(userDetails);
given(userDetails.getUsername()).willReturn(user.getUsername());
userIsAdmin();
// when then
given(userRepo.findByUsername(adminUser.getUsername())).willReturn(adminUser);
assertThatThrownBy(() -> authService.deleteUser(new DeleteAccountDto(adminUser.getUsername())))
.isInstanceOf(AccountException.class)
.hasMessage("Administrators can't be deleted");
}
@Test
void deleteUser_GivenLoggedInUserIsAdmin_WhenTryingToDeleteOtherAdmin_ThenThrowError() {
userIsAdmin();
given(securityContext.getAuthentication().getPrincipal()).willReturn(userDetails);
given(userDetails.getUsername()).willReturn(user.getUsername());
given(userRepo.findByUsername(otherAdminUser.getUsername())).willReturn(otherAdminUser);
// when then
assertThatThrownBy(() -> authService.deleteUser(new DeleteAccountDto(otherAdminUser.getUsername())))
.isInstanceOf(AccountException.class)
.hasMessage("Admins can't be deleted");
}
Same thing applies for custom queries. Just try to test all your logic in your service-class
I hope this answers your question.