Mockito
@Mock
private UserRepository userRepository;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
JwtUtil jwtUtil;
private HttpServletResponse res;
@InjectMocks
private UserService userService;
@Captor
private ArgumentCaptor<User> userCaptor;
@Mock
테스트 대상 클래스에서 사용되는 외부 의존성을 대체, 특정 객체에 의존하고 있을때, 주입하는 대신에 @Mock을 사용해 객체를 생성할 수 있다.
실제 객체와 동일한 인터페이스를 가지고 있지만, 동작은 직접 정의할 수 있다. (테스트의 격리성 유지)
실제 동작이 구현되어 있지 않으므로 Mock객체의 동작을 정의해야한다.
when - then / given - willReturn
when(mockObject.methodCall(argument)).thenReturn(value);
given(mockObject.methodCall(argument)).willReturn(value);
- mockObject : 목의 객체
- methodCall : 객체에서 호출될 메서드
- argument : 메서드의 매개변수
- value : 반환값
@InjectMocks
필드 클래스에대한 의존성을 주입한다.
생성자를 통한 주입과는 다르게 생성자가 호출되지 않는다.
따라서 생성자에서 초기화되는 의존성이 있는 경우, 초기화 할 수 없으니 주의!
@Captor
Mockito에서 제공하는 애노테이셔느로, 메서드 호출 시 전달된 인자를 캡쳐해 검증할 수 있도록한다.
주로 verify 메서드와 함께 사용된다.
- 서비스 로직
@Transactional
public void signup(SignupRequestDto requestDto) {
String username = requestDto.getUsername();
String password = passwordEncoder.encode(requestDto.getPassword());
UserRoleEnum role = requestDto.getRole();
userRepository.save(new User(username, password,role));
}
- 테스트 코드
@Captor
private ArgumentCaptor<User> user;
@Test
void signup() {
// give
SignupRequestDto signupRequestDto = new SignupRequestDto();
signupRequestDto.setUsername("rjsld");
signupRequestDto.setPassword("1234");
signupRequestDto.setRole(UserRoleEnum.USER);
when(passwordEncoder.encode("1234")).thenReturn("encodedPassword");
// when
userService.signup(signupRequestDto);
// then
verify(userRepository).save(userCaptor.capture());
User testUser = userCaptor.getValue();
assertEquals("rjsld 와", testUser.getUsername()+"는 같습니다.");
}
userRepository.save() 메서드가 호출될때 전달된 User 객체를 @Captor의 userCaptor에 저장한다.
verify ~ 코드를 통해 한 번 호출되었는지 검증하면서 메서드 호출 시 전달된 User객체를 검증할 수 있다.
getValue()를 통해 캡처한 값을 가져올 수 있다.
@Test
void updateProfile() {
// give
Long id = 1L;
UserRequestDto userRequestDto = new UserRequestDto();
userRequestDto.setPassword("1234");
userRequestDto.setIntro("반갑습니다.");
String encodePassword = "4321";
User user = new User(id,"rjsld",encodePassword,"안녕하세요");
given(userRepository.findById(id)).willReturn(Optional.of(user));
given(passwordEncoder.matches("1234", encodePassword)).willReturn(true);
given(passwordEncoder.encode("1234")).willReturn(encodePassword);
// when
userService.updateProfile(id,userRequestDto);
assertEquals("반갑습니다 = ", user.getIntro());
}
- 서비스 로직
//프로필 수정
@Transactional
public UserResponseDto updateProfile(Long id, UserRequestDto dto) {
User user = checkPWAndGet(id, dto.getPassword());
user.setPassword(passwordEncoder.encode(dto.getPassword()));
user.setIntro(dto.getIntro());
return new UserResponseDto(user);
}
// //프로필 비밀번호 체크
private User checkPWAndGet(Long id, String password) {
User user = getUser(id);
// 비밀번호 체크
if (!passwordEncoder.matches(password,user.getPassword())) {
throw new IllegalArgumentException("잘못된 비밀번호입니다.");
}
// if (user.getPassword() != null && !Objects.equals(user.getPassword(),password)) {
// throw new IllegalArgumentException();
// }
return user;
}
- 테스트 코드
@Test
void updateProfile() {
// give
Long id = 1L;
UserRequestDto userRequestDto = new UserRequestDto();
userRequestDto.setPassword("1234");
userRequestDto.setIntro("반갑습니다.");
String encodePassword = "4321";
User user = new User(id,"rjsld",encodePassword,"안녕하세요");
given(userRepository.findById(id)).willReturn(Optional.of(user));
given(passwordEncoder.matches("1234", encodePassword)).willReturn(true);
// given(passwordEncoder.encode("1234")).willReturn(encodePassword);
// when
userService.updateProfile(id,userRequestDto);
assertEquals("반갑습니다 = ", user.getIntro());
}
암호화된 비밀번호를 matches() 메서드를 사용해 두 값을 인자로 받았을때 항상 true가 나오도록 설정한다.
'개발 일지 > Day by day' 카테고리의 다른 글
2024-02-06 TIL (0) | 2024.02.06 |
---|---|
2024-01-31 TIL (0) | 2024.01.31 |
2024-01-26 TIL (1) | 2024.01.26 |
2024-01-23 TIL (1) | 2024.01.24 |
2024-01-18 TIL (0) | 2024.01.18 |