Mockito
는 이러한 Test Double을 지원하기 위해, 개발자가 동작을 직접 제어할 수 있는 가짜(Mock) 객체를 지원하는 테스트 프레임워크이다. 일반적으로 Spring으로 웹 애플리케이션을 개발하면, 여러 객체들 간의 의존성이 생긴다. 이러한 의존성은 단위 테스트를 작성을 어렵게 하는데, 이를 해결하기 위해 가짜 객체를 주입시켜주는 Mockito 라이브러리를 활용할 수 있다.Mockito에서 Mock(가짜) 객체의 의존성 주입을 위해서는 크게 3가지 어노테이션이 사용된다.
@Mock
: Mock 객체를 만들어 반환해주는 어노테이션@Spy
: Stub하지 않고 실제 메서드의 기능을 그대로 사용하는 어노테이션 (실제 인스턴스를 사용하여 mocking)@InjectMocks
: @Mock 또는 @Spy로 생성된 가짜 객체를 자동으로 주입시켜주는 어노테이션@ExtendWith(MockitoExtension.class)
class BoardLikeServiceTest {
@Mock
private BoardQuery boardQuery;
@Mock
private BoardLikeQuery boardLikeQuery;
@Mock
private UserCommand userCommand;
@Mock
private BoardCommand boardCommand;
@InjectMocks
private BoardLikeService boardLikeService;
@MockBean
: @MockBean은 스프링 컨텍스트에 mock객체를 등록하고 스프링 컨텍스트에 의해 @Autowired
가 동작할 때, 등록된 mock객체를 사용@MockBean
private OrderRepository orderRepository;
@MockBean
private Notification notification;
@Autowired // @MockBean으로 등록한 mock객체를 주입받아 의존성 해결
private OrderService orderService;
@SpyBean
: ApplicationContext에 spy객체를 추가예를 들어 UserController에 대한 단위 테스트를 작성하고자 할 때, UserService를 사용하고 있다면 @Mock 어노테이션을 통해 가짜 UserService를 만들고, @InjectMocks를 통해 UserController에 이를 주입시킬 수 있다.
Junit5으로 테스트를 진행하기 위해서는 @ExtendWith(MockitoExtension.class)
를 사용해야 한다.
의존성이 있는 객체는 가짜 객체(Mock Object)를 주입하여 어떤 결과를 반환하는 것을 stubbing라고 한다. Mockito에서는 다음과 같은 stub 메소드를 제공한다.
// 모의 객체의 메서드 호출에 대한 동작 정의, someMethod()내에 다른 메서드에 대해서도
when()으로 정의해주어야 한다.
when(someService.someMethod()).thenReturn("Mocked Result");
// 모의 객체를 사용하여 테스트 수행
String result = someService.someMethod();
// result는 "Mocked Result"와 같아야 함
verify(mockObject, times(expectedNumberOfInvocations)).methodName(argumentMatchers);
mockObject
: 검증할 메서드 호출이 발생한 특정 목(Mock) 객체입니다.
times()
: 메서드 호출이 몇 번 일어나야 하는지를 지정합니다. 예를 들어, times(1)은 한 번 호출되어야 함을 의미하고, times(2)는 두 번 호출되어야 함을 의미합니다.
methodName
: 검증하려는 메서드의 이름입니다.
argumentMatchers (선택사항)
: 메서드 호출의 인자에 대한 검증 조건을 지정합니다. 예를 들어, eq(expectedArgument)을 사용하여 특정 인자가 예상한 값과 일치해야 한다고 지정할 수 있습니다.
@RestController
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
// UserController가 UserService에 의존성을 가지는 상황
@PostMapping("/users/signUp")
public ResponseEntity<UserResponse> signUp(@RequestBody SignUpRequest request) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(userService.signUp(request));
}
@GetMapping("/users")
public ResponseEntity<List<UserResponse>> findAll() {
return ResponseEntity.ok(userService.findAll());
}
}
이렇게 주입
@ExtendWith(MockitoExtension.class)
class UserControllerTest {
@InjectMocks
// Mock를 여기에 주입해라 그럼 UserController에서 UserService를 찾아서
의존성 주입(즉, 해당 클래스안에서 정의된 mock객체를 찾아서 의존성을 해결)
private UserController userController;
@Mock
private UserService userService;
}
참고
https://mangkyu.tistory.com/145
https://cobbybb.tistory.com/16