I have written a testcase in which I mock a object using mockk. The problem is that when I run the testcase and debug using Intellij I do get the mocked response inside the debug window but when I let the testcase finish I get an error of my database client (so it ran the actual method instead).
The following is my simplified service code:
class SendMessageService (
private val authHelper: AuthHelper
) {
companion object {
val targetsDb = TargetsDynamodbService()
}
fun handlePushIdRequest(sendMessageRequest: SendMessageRequest): Observable<List<Target>> {
if (!validAuthorization(sendMessageRequest.serviceKey)) {
throw ClientErrorException("Invalid Authorization", Response.Status.UNAUTHORIZED)
}
return targetsDb.getAllTargetsAsObservable(sendMessageRequest.pushId)
}
private fun validAuthorization(serviceKey: ServiceKey): Boolean {
val authorization = authHelper.getTargetId("service key")
return authorization == Configuration.SendMessageAuthorization.authorization(serviceKey)
}
}
With this as simplified testcase:
class SendMessageServiceTest : AbstractServiceTest() {
private val authHelper = AuthHelper(listOf("abc"))
private val targetsDynamodbService: TargetsDynamodbService = mockk()
private lateinit var service: SendMessageService
@BeforeEach
fun setUp() {
mockkObject(SendMessageService.Companion)
every { SendMessageService.Companion.targetsDb } returns targetsDynamodbService
ConfigurationManager.getConfigInstance().setProperty("sendmessage.authorization.test", "abc")
}
@Test
fun `successfully send pushId request message`() {
every { targetsDynamodbService.getAllTargetsAsObservable(any()) } answers {
Observable.just(listOf(Target().apply { pushId = arg<String>(0) }))
}
service = SendMessageService(authHelper)
val response = service.handlePushIdRequests(createMessageRequest()).blockingFirst()
assertTrue(response.isNotEmpty())
}
private fun createMessageRequest() =
SendMessageRequest(
pushId = "pushId",
serviceKey = ServiceKey.TEST,
title = TextLocalization("en", "nl"),
body = TextLocalization("en", "nl"),
silent = false,
collapseKey = null,
data = null,
androidOptions = null,
iosOptions = null
)
}
What am I missing that a debug and the actual testcase result can differ?
every { ... }
mocks a function, not a field. In your particular case Kotlin compiler doesn't generate getter and setter for a field because it's not required.
So to solve your problem you have to force compiler to generate getter (which is a function) for the desired property, e.g. using by lazy
:
Trick #1
companion object {
val targetsDb by lazy { TargetsDynamodbService() }
}
... or to declare getter explicitly:
Trick #2
companion object {
private val _targetsDb = TargetsDynamodbService() // backing field
val targetsDb: TargetsDynamodbService
get() = _targetsDb // get() is an explicit getter for _targetsDb
}
P.S. However, I'd recommend you to review the design of your class, and consider about injecting targetsDb
through constructor rather than instantiating it inside Companion object.