I want to use any() inside then method. Here is my test code:
@ExtendWith(MockitoExtension::class)
internal class UserSignInProviderTest {
@Mock
lateinit var authApiClient: AuthApiClient
@Mock
lateinit var userRepository: UserRepository
@InjectMocks
lateinit var userSignInProvider: UserSignInProvider
@BeforeEach
internal fun setUp() {
userSignInProvider = UserSignInProvider(userRepository, authApiClient)
}
...
}
There are 3 stubs here. In the first stub, you can use anyLong inside then.
@Test
fun refreshTokenTest() {
// given.1
whenever(authApiClient.validateRefreshToken(anyString())).then {
println(">>> authApiClient.validateRefreshToken")
return@then RefreshTokenValidateResponse(
payload = RefreshTokenValidateResponse.Payload(anyLong())
)
}
...
}
However, it was not available for the second and third stubs. I want to know why it can't be used. Or I want to know how to use it.
// given.2
whenever(authApiClient.refreshToken(any())).then {
println(">>> authApiClient.refreshToken")
return@then ResponseEntity.ok().body(
IssueTokenResponse(
payload = IssueTokenResponse.Payload(
"any-string",
99,
"any-string"
)
)
)
}
// given.3
val user = User(
id = 999,
email = "any-string",
name = "any-string"
)
whenever(userRepository.findById(anyLong())).then {
Optional.of(user)
}
// when
userSignInProvider.refreshToken(anyString())
// then
verify(authApiClient, times(1)).validateRefreshToken(anyString())
verify(authApiClient, times(1)).refreshToken(any())
Of course, I tried the eq method instead of String("any-string"), but I got this error.
whenever(authApiClient.refreshToken(any())).then {
println(">>> authApiClient.refreshToken")
return@then ResponseEntity.ok().body(
IssueTokenResponse(
payload = IssueTokenResponse.Payload(eq("any-string"), anyLong(), eq("any-string"))
)
)
}
// Error
java.lang.NullPointerException: eq("any-string") must not be null
CodePudding user response:
Regarding your main question, why any()
or eq()
cannot be used
As mentioned in other answers, any()
or eq()
is returning null but your class expected a non-null value, therefore Kotlin throws an exception.
However, a more important concept to be clarified is the behaviour of any()
or eq()
.
They are not using to present any string or any value in the then
block. So even you use them in then
block they just a simple value. any()
or eq()
are for matching method parameters, they are expected to be used in
whenever()
: during the test if the mock is being called an, the mocking framework will do the matching for you, e.g.
whenever(authApiClient.validateRefreshToken(eq("abc"))).thenReturn(something())
//
authApiClient.validateRefreshToken("abc") // returns something()
authApiClient.validateRefreshToken("qwe") // cannot return something()
verify(xxx).method(any())
: mocking framework records the interaction to the mock object within the test. This verify checks the interaction and then use theany()
to verify does the interactions align with you matcher. e.g.
// during the test, below is called once
authApiClient.validateRefreshToken("any-string")
// in the test
verify(authApiClient, times(1)).validateRefreshToken(eq("abc")) // assertion fail
verify(authApiClient, times(1)).validateRefreshToken(eq("any-string")) // assertion success
verify(authApiClient, times(1)).validateRefreshToken(anyString()) // assertion success
To conclude, you don't need to return an instance with any()
or eq()
in the then block. Instead, you need put then in the whenever
or verify
to make the mocking framework behaves as what you expected.
CodePudding user response:
Mockito doesn't allow to mix raw values and matchers.
try with matchers :
// given.2
payload = IssueTokenResponse.Payload(eq("any-string"), anyLong(), eq("any-string"))