Issue
I'm learning testing in spring boot, i have this test:
@ExtendWith(MockitoExtension.class)
@SpringBootTest
class AppUserServiceTest {
@Mock
private UserRepository repository;
private UserService userService;
@BeforeEach
void setUp() {
userService = new UserService(repository);
}
@Test
void itShouldLoadUsernameByName() {
AppUser appUser = new AppUser(
ApplicationRole.USER,
"leonardo",
"rossi",
"leo__",
"[email protected]",
"password"
);
repository.save(appUser);
userService.loadUserByUsername(appUser.getUsername());
verify(repository).searchByUserName(appUser.getUsername());
}
}
it keep throwing me an exception because it doesn't find any user in the database, in fact even if i save the user the repository.findAll() return 0 element.
This is my User service that i'm trying to test:
@AllArgsConstructor
@Service
public class UserService
implements UserDetailsService {
private final UserRepository repository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return repository.searchByUserName(username)
.orElseThrow(
()-> new UsernameNotFoundException("The username " + username + " has not been found")
);
}
This is my H2 databse for testing configuration:
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Solution
A mock is just a mock. It's never actually doing something. It just can behave like a real thing, but you have to tell the mock how to do it.
So if you mock the UserRepository and try to save something nothing will happen. Because again, a mock never actually does something. The advantage of this is that you don't actually need the whole infrastructure to unit test a tiny method. Additionally the test gets independent of data. What you can do now is return some data if some method is called.
In your case, you don't need a whole database to test the functionality of the UserService. Thus mocking the repository is a good option. Now since it's a mock you have to tell the mock how to behave for your test case:
@Test
void itShouldLoadUsernameByName() {
AppUser appUser = new AppUser(
ApplicationRole.USER,
"leonardo",
"rossi",
"leo__",
"[email protected]",
"password"
);
when(standortRepository.searchByUserName(any())).thenReturn(appUser);
userService.loadUserByUsername(appUser.getUsername());
//More expectations ...
verify(repository).searchByUserName(appUser.getUsername());
}
Now what I have done is to tell the mock it should return the appUser, when the Method loadByUsername
is called.
P.s. these are the static imports I used:
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
Answered By - berse2212
Answer Checked By - David Goodson (JavaFixing Volunteer)