@MockBean vs @Mock,@InjectMocks
refreshAccressToken(..) 메서드와 createAccessToken(..) 메서드의 결과값이 같은지 확인하고 싶어 테스트 코드를 작성하였다.
@RequiredArgsConstructor
@Slf4j
@Service
public class JwtService {
private final UserService userService;
public String refreshAccressToken(String token){
validateToken(token);
Account find = userService.find(token);
return createAccessToken(find.getUserId(), find.getName());
}
public String createAccessToken(String userEmail, String name){
Claims claims = Jwts.claims()
.add("name", name)
.add("email", userEmail)
.add("auth", RoleUser.ADMIN.getValue())
.build();
Date now = new Date();
String token = Jwts.builder()
.subject(ACCESS_TOKEN_SUBJECT)
.claims(claims)
.issuedAt(now)
.expiration(new Date(now.getTime() + TOKEN_EXPIRE_TIME*3600)) //1시간
.signWith(getSignKey())
.compact();
return token;
}
Test Code
@SpringBootTest
public class JwtServiceTests {
@Mock
private UserService userService; // userService를 mock합니다.
@InjectMocks
private JwtService jwtService; // 테스트할 TokenService
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this); // Mock 객체 초기화
}
@Test
public void tokenDiffTest(){
//given
String email = "jyyoon@gmail.com";
String name = "윤주영";
String createToken = jwtService.createAccessToken(email, name);
Account account = Account.builder()
.userId(email)
.name(name)
.role(RoleUser.USER)
.provider("네이버")
.build();
when(userService.find(createToken)).thenReturn(account);
String refreshToken = jwtService.refreshAccressToken(createToken);
...
}
}
테스트 하려던 메서드들은 JwtService 클래스의 메서드이고, refreshAccressToken(..) 메서드에서는 db조회하는 userService.find(token)
코드가 있었다.
나는 테스트시, 직접 db조회가 되는것이 싫었기 때문에 가상으로 만들어주고 싶어서 @Mock
을 사용하여 UserService를 mocking 해주었다.
userService.find(token)
결과 값은 가상으로 when(userService.find(createToken)).thenReturn(account)
만들도록 when
을 사용했다.
그러나 db조회 코드가 내가 원하는 값으로 mocking 되지 않고 null로 되었다.
왜 내가 원하는 값으로 mocking되지 않았지?????
조사결과 아래와 같은 차이점이 있다.
1. @Mock
- 역할:
- Mockito의 Mock 객체를 생성합니다.
- 테스트에서 특정 객체의 동작을 Mocking하여 제어할 수 있습니다.
- Spring Context에 영향을 미치지 않습니다.
- 사용 환경:
- Spring Context가 필요하지 않은 단위 테스트(Unit Test)에서 주로 사용됩니다.
2. @InjectMocks
- 역할:
- 테스트 대상 클래스에
@Mock
으로 선언된 Mock 객체를 자동으로 주입합니다. - 의존성이 있는 실제 객체 대신 Mock 객체를 주입하여 테스트 환경을 설정합니다.
- 테스트 대상 클래스에
- 사용 환경:
- Mock 객체가 여러 개 필요하고, 이 객체들을 테스트 대상 클래스에 주입해야 하는 경우 사용됩니다.
3. @MockBean
- 역할:
- Spring Context에 Mock 객체를 주입합니다.
- 테스트 대상이 실제 Spring Context와 연동되어야 하는 경우(예:
@Service
,@Repository
) 사용됩니다.
- 사용 환경:
- Spring Boot 통합 테스트(Integration Test)에서 사용됩니다.
@SpringBootTest
,@WebMvcTest
,@DataJpaTest
등과 함께 사용됩니다.- Spring Context 내의 Bean을 Mocking해야 할 때 적합합니다.
정리
언제 사용해야 할까?
Spring Context가 필요 없는 단위 테스트:
@Mock
과@InjectMocks
를 사용합니다.- Spring Context 로딩 없이 테스트를 빠르게 수행할 수 있습니다.
Spring Context가 필요한 통합 테스트:
@MockBean
을 사용합니다.- Spring 빈 간의 의존성을 유지하면서 특정 빈만 Mocking할 수 있습니다.
@Mock
과 @InjectMocks
은 @SpringBootTest
와 혼용하여 사용하지 않도록 주의하자.
@InjectMocks
는 Mockito가 생성하고 관리한다.
Spring과 무관한 단위 테스트에 적합하며, Spring Context를 사용하지 않습니다.
Spring Context와 관련된 테스트를 하려면 @MockBean
을 사용하는 것이 적합하다.
@InjectMocks
주입 예시
@ExtendWith(MockitoExtension.class)
public class ExampleTest {
@Mock
private UserService userService; // Mockito가 관리
@InjectMocks
private UserController userController; // Mockito가 관리
@Test
public void testExample() {
when(userService.getUserName(1L)).thenReturn("윤주영");
String result = userController.getUserName(1L);
assertEquals("윤주영", result); // 정상 작동
}
}
그래서 어떻게 수정함?
@SpringBootTest
public class JwtServiceTests {
@MockBean
private UserService userService; // userService를 mock합니다.
@Autowired
private JwtService jwtService; // 테스트할 TokenService
@Test
public void tokenDiffTest(){
//given
String email = "jyyoon@gmail.com";
String name = "윤주영";
String createToken = jwtService.createAccessToken(email, name);
Account account = Account.builder()
.userId(email)
.name(name)
.role(RoleUser.USER)
.provider("네이버")
.build();
when(userService.find(createToken)).thenReturn(account);
String refreshToken = jwtService.refreshAccressToken(createToken);
assertNotNull(refreshToken); // 결과 토큰이 null이 아님을 확인
...
...
}
}
'SPRING > 스프링부트' 카테고리의 다른 글
Spring에서 request에 대한 검증 방법 2가지 (0) | 2024.05.07 |
---|---|
RestTemplate, Spring MVC vs WebClient, Spring WebFlux 성능테스트 (0) | 2024.04.04 |
동시성 해결방법 (0) | 2024.03.26 |
로컬,개발,운영 yml를 하나로 통합 및 프로퍼티 호출시 @Value의 장단점 및 대체재 (0) | 2023.08.09 |
Prometheus & Grafana & Spring boot 모니티링 하기 (0) | 2023.07.31 |