자바칩

[Spring] @InjectMocks 와 @Mock 의 차이점 본문

Study/Spring

[Spring] @InjectMocks 와 @Mock 의 차이점

아기제이 2024. 7. 19. 03:19
728x90

@InjectMocks와 @Mock 어노테이션의 사용은 각기 다른 목적을 가지고 있습니다. 이를 통해 단위 테스트에서 객체 간의 의존성을 효과적으로 관리하고, 테스트 대상 객체와 그 의존 객체를 올바르게 설정할 수 있습니다.

@Mock

  • 역할: 특정 클래스의 목(mock) 객체를 생성합니다.
  • 사용 위치: 테스트에서 사용되는 의존 객체에 대해 사용됩니다.
  • 목적: 목 객체를 통해 실제 객체의 동작을 시뮬레이션하고, 특정 메서드 호출에 대해 정의된 동작을 수행하도록 합니다.
 
    @Mock
    private UserRepository userRepository;

    @Mock
    private PasswordEncoder passwordEncoder;
 

 

위 예시에서는 UserRepository와 PasswordEncoder가 목 객체로 생성되었습니다. 이는 실제 객체를 대체하여 메서드 호출 시 원하는 동작을 정의할 수 있게 합니다.

@InjectMocks

  • 역할: 테스트 대상 객체를 생성하고, 이 객체의 의존성을 자동으로 주입합니다.
  • 사용 위치: 테스트 대상 클래스에 대해 사용됩니다.
  • 목적: 의존성이 있는 객체를 주입받아, 테스트 대상 클래스의 실제 동작을 검증할 수 있도록 합니다.
 
 
    @InjectMocks
    private UserService userService;
 
 
위 예시에서는 UserService 객체가 생성되고, @Mock으로 정의된 객체들이 UserService의 의존성으로 주입됩니다. 이렇게 하면 UserService는 실제 실행될 때와 동일한 의존성을 가지게 되어, 목 객체와의 상호작용을 통해 그 동작을 검증할 수 있습니다.

종합 예시

 
    @RunWith(MockitoJUnitRunner.class)
    public class UserServiceTest {

        @InjectMocks
        private UserService userService;

        @Mock
        private UserRepository userRepository;

        @Mock
        private PasswordEncoder passwordEncoder;

        @Test
        public void createUser_success() {
            // Given: 사용자 정보 설정
            UserDto userDto = new UserDto();
            userDto.setUsername("newUser");
            userDto.setPassword1("password");
            userDto.setPassword2("password");

            // When: 목 객체의 동작 정의
            when(userRepository.findByUsername(userDto.getUsername())).thenReturn(Optional.empty());
            when(passwordEncoder.encode(userDto.getPassword1())).thenReturn("encodedPassword");

            // 목 객체가 반환할 사용자 설정
            User savedUser = new User();
            savedUser.setId(1L);
            when(userRepository.save(any(User.class))).thenReturn(savedUser);

            // Then: 서비스 메서드 호출 및 결과 검증
            Long userId = userService.createUser(userDto);

            // 결과가 예상대로인지 검증
            assertEquals(1L, userId);

            // save 메서드가 정확히 한 번 호출되었는지 검증
            verify(userRepository, times(1)).save(any(User.class));
        }
    }
 

 

verify는 Mockito 라이브러리에서 제공하는 메서드로, 특정 메서드가 호출되었는지 확인하는 데 사용됩니다. 테스트 중에 메서드 호출 여부와 호출 횟수를 검증할 수 있습니다. 이를 통해 특정 조건에서 메서드가 제대로 호출되었는지 확인하여 코드의 동작을 검증할 수 있습니다.

결론

  • @Mock: 의존 객체를 목(mock) 객체로 생성하여 메서드 호출에 대한 동작을 정의합니다.
  • @InjectMocks: 테스트 대상 객체를 생성하고, 목 객체들을 해당 객체의 의존성으로 주입합니다.

이렇게 함으로써, UserService 클래스는 테스트 환경에서 실제 환경과 유사한 의존성을 가지게 되어, 그 동작을 검증할 수 있습니다.


 

테스트 코드를 처음 작성해보면서 @Mock과 @InjectMocks을 왜 따로 쓰는 것일까 궁금해서 찾아보았다.

@Mock 객체 (테스트에 사용되는 의존 객체) -> @InjectMocks (테스트 대상 객체) 에 주입

이름 앞에 Inject(주입)를 다는 이유는 다 있는 것이구나 싶다.