Mockito에서 only과 time(1)은 어떤 차이일까?
728x90
반응형

 

스프링에서 Mock을 활용한 테스트를 할 때, Mockito를 가장 많이 사용할 것이다. 그리고 검증 로직을 만들 때 호출 횟수 기준으로 테스트 코드를 짜는 경우가 있다.

 

// when
userService.create(userSignUpRequest)
// then
verify(userRepository, times(1)).save(any<User>())
verify(emailSender, only()).send(any(), any())

 

 

처음에는 2가지 모두 1회만 사용한다는 점에서 동일한 용도가 아닐까 했다. 즉 아래와 같다.

 

// userRepository라는 Mock bean은 save를 1회만 호출한다
verify(userRepository, times(1)).save(any<User>())
// emailSender라는 Mock bean은 send를 1회만 호출한다
verify(emailSender, only()).send(any(), any())

 

그렇다면 times를 사용한 부분을 only로 바꿔도 되지 않을까? 그렇게 생각해서 변경했더니 아래와 같은 에러가 나타났다. 왜 이런 에러가 나타날까?

 

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

Cannot invoke "org.mockito.invocation.Invocation.getMock()" because "undesired" is null
java.lang.NullPointerException: Cannot invoke "org.mockito.invocation.Invocation.getMock()" because "undesired" is null

 

이유는 times(1)와 only은 용도의 차이가 있기 때문이다.

  • times(1)는 원래 생각했던 것처럼 해당 mock bean의 method를 1회만 호출한다는 의미가 맞다.
  • only은 해당 mock bean에서 오로지 지정된 method만 호출하는지 확인하는 의도를 가진다.

 

when 구문의 userService.create 로직을 살펴보자.

fun creaet(request: UserSignUpRequest) {
    userRepository.findByUsername(username)?.let {
        throw DuplicateUsernameException() // Custome하게 만든 Exception
    }
    val user = User.create(request)
    userRepository.save(user)
    emailSender.send(user, request)
}

 

userRepository는 2번의 사용(findByUsername, save)이 있었다. 그래서 원하는 method의 횟수 검증을 하려면 only을 사용할 수 없고 times를 사용해야한다. 하지만 emailSender는 오로지 send 함수만 사용한다. 해당 Bean이 단 하나의 함수만 사용하는지 검증하기 위해 only을 사용할 수 있기에 emailSender에는 only을 적용할 수 있다.

728x90
반응형