title: MockK: How to mock an already tested method called inside another method under test (Kotlin)
body: <p>I want to test following method:</p>
  <pre><code>@Transactional
    override suspend fun updateDebtWithoutDocumentsByUserId(userId: Long, dtoIn: DebtDTO): DebtDTO {
      if (dtoIn.id == null) {
        throw NotFoundException(&quot;Can only update existing debt&quot;)
      }
      val d = debtRepository.findById(dtoIn.id) ?: throw NotFoundException(&quot;Could not find debt ${dtoIn.id}&quot;)
      val updated = debtRepository.save(
        d.copy(
          title = dtoIn.title,
          amount = dtoIn.amount,
          category = dtoIn.category,
        )
      )
      if (dtoIn.amount != d.amount) {
        // update potentially existing installment plan.
        // Note that this guarantees that the installment amount is kept in bounds and all installment records are updated
        // accordingly.
        val installmentPlan = installmentPlanRepository.findByDebtId(dtoIn.id)
        if (installmentPlan != null) {
          val installmentRecordIds: List&lt;Long&gt; = installmentRepository.findByDebtId(dtoIn.id)
            .toList()
            .map { it.recordId }
          storeInstallmentPlan(dtoIn.id, InstallmentPlanDTO.from(installmentPlan, installmentRecordIds))
            .collect() // ensure that the flow is executed.
        }
      }
      val documents = debtDocumentRepository.findByDebtId(dtoIn.id)
        .toSet()
        .map { DocumentDTO.from(it) }
        .associateBy { it.id!! }
      return DebtDTO.from(updated, documents)
    }
  </code></pre>
  <p>If there is an <strong>installment plan available</strong> the method <code>storeInstallmentPlan(dtoIn.id, InstallmentPlanDTO.from(installmentPlan, installmentRecordIds))</code> will be called. The original method <code>storeInstallmentPlan</code> is already tested.</p>
  <p>How can I mock <code>storeInstallmentPlan</code> inside my unit I want to test without repeat myself by testing <code>storeInstallmentPlan</code> again? I think I have to somehow use <code>SpyK</code> for doing this, but I don't know exactly how to do it. Maybe someone has a solution for me.</p>
  <p>Thanks :)</p>
  <hr />
  <p>Here my <strong>full test class</strong>:</p>
  <pre><code>@ExtendWith(MockKExtension::class)
  internal class PlanServiceFeatureImplTest {
  
    @MockK
    lateinit var debtRepository: DebtRepository
  
    @MockK
    lateinit var debtDocumentRepository: DebtDocumentRepository
  
    @MockK
    lateinit var installmentPlanRepository: InstallmentPlanRepository
  
    @MockK
    lateinit var installmentRepository: InstallmentRepository
  
    @MockK
    lateinit var recordService: RecordService
  
    @MockK
    lateinit var userService: UserService
  
    @InjectMockKs
    lateinit var planService: PlanServiceFeatureImpl
  
    @Test
    fun `updateDebtWithoutDocumentsByUserId ok - no installment plan available`() {
      val userId = 123L
      val dtoIn = DebtDTO(
        id = 1L,
        title = &quot;debt1New&quot;,
        amount = BigDecimal.valueOf(2000),
        category = DebtCategory.dangerous,
        documents = mapOf(),
      )
      val oldDebt = Debt(
        id = 1L,
        userId = userId,
        title = &quot;debt1&quot;,
        amount = BigDecimal.valueOf(1000),
        category = DebtCategory.credit,
      )
      assertThat(dtoIn.title).isNotEqualTo(oldDebt.title)
      assertThat(dtoIn.amount).isNotEqualTo(oldDebt.amount)
      assertThat(dtoIn.category).isNotEqualTo(oldDebt.category)
  
      coEvery { debtRepository.findById(dtoIn.id!!) } returns oldDebt
      val doc1 = DebtDocument(
        id = 11L,
        debtId = dtoIn.id!!,
        title = &quot;doc1&quot;,
        bytes = byteArrayOf(0x01),
      )
      coEvery { debtRepository.save(any()) } answers { arg(0) }
      coEvery { debtDocumentRepository.findByDebtId(dtoIn.id!!) } returns flowOf(doc1)
  
      //no installment plan available
      coEvery { installmentPlanRepository.findByDebtId(dtoIn.id!!) } returns null
  
      runBlocking {
        val actual = planService.updateDebtWithoutDocumentsByUserId(userId, dtoIn)
        assertThat(actual).isEqualTo(
          dtoIn.copy(
            documents = mapOf(doc1.id!! to DocumentDTO.from(doc1)),
          )
        )
      }
      coVerify {
        debtRepository.save(withArg {
          assertThat(it.id).isEqualTo(dtoIn.id)
          assertThat(it.userId).isEqualTo(userId)
          assertThat(it.title).isEqualTo(dtoIn.title)
          assertThat(it.amount).isEqualTo(dtoIn.amount)
          assertThat(it.category).isEqualTo(dtoIn.category)
        })
      }
    }
  
    @Test
    fun `updateDebtWithoutDocumentsByUserId ok - installment plan available`() {
      val userId = 123L
      val dtoIn = DebtDTO(
        id = 1L,
        title = &quot;debt1New&quot;,
        amount = BigDecimal.valueOf(2000),
        category = DebtCategory.dangerous,
        documents = mapOf(),
      )
      val oldDebt = Debt(
        id = 1L,
        userId = userId,
        title = &quot;debt1&quot;,
        amount = BigDecimal.valueOf(1000),
        category = DebtCategory.credit,
      )
      assertThat(dtoIn.title).isNotEqualTo(oldDebt.title)
      assertThat(dtoIn.amount).isNotEqualTo(oldDebt.amount)
      assertThat(dtoIn.category).isNotEqualTo(oldDebt.category)
  
      coEvery { debtRepository.findById(dtoIn.id!!) } returns oldDebt
      val doc1 = DebtDocument(
        id = 11L,
        debtId = dtoIn.id!!,
        title = &quot;doc1&quot;,
        bytes = byteArrayOf(0x01),
      )
      coEvery { debtRepository.save(any()) } answers { arg(0) }
      coEvery { debtDocumentRepository.findByDebtId(dtoIn.id!!) } returns flowOf(doc1)
  
      //installment plan available
      val plan = mockk&lt;InstallmentPlan&gt;()
      coEvery { installmentPlanRepository.findByDebtId(dtoIn.id!!) } returns plan
      coEvery { installmentRepository.findByDebtId(dtoIn.id!!) } returns flowOf()
      /*
  
                  Here I need to test storeInstallmentPlan / mock of it
  
       */
  
      runBlocking {
        val actual = planService.updateDebtWithoutDocumentsByUserId(userId, dtoIn)
        assertThat(actual).isEqualTo(
          dtoIn.copy(
            documents = mapOf(doc1.id!! to DocumentDTO.from(doc1)),
          )
        )
      }
      coVerify {
        debtRepository.save(withArg {
          assertThat(it.id).isEqualTo(dtoIn.id)
          assertThat(it.userId).isEqualTo(userId)
          assertThat(it.title).isEqualTo(dtoIn.title)
          assertThat(it.amount).isEqualTo(dtoIn.amount)
          assertThat(it.category).isEqualTo(dtoIn.category)
        })
      }
    }
  
    @Test
    fun `storeInstallmentPlan ok`(@MockK user: User) {
      val debtId = 123L
      val debtAmount = BigDecimal.valueOf(1000)
      val installmentAmount = BigDecimal.valueOf(500)
      val interval = Repeat.monthly
  
      val firstPaymentDate = LocalDate.of(2021, 12, 27)
        .atStartOfDay(Time.DEFAULT_TIME_ZONE).toOffsetDateTime()
  
      val planDTO = InstallmentPlanDTO(
        interval = interval,
        firstPaymentDate = firstPaymentDate,
        amount = installmentAmount,
        installments = listOf()
      )
      val debt = Debt(
        userId = 32L,
        title = &quot;debt1&quot;,
        amount = debtAmount,
        category = DebtCategory.credit
      )
      val plan = InstallmentPlan(
        id = 122L,
        debtId = debtId,
        interval = interval,
        firstPaymentDate = firstPaymentDate,
        amount = installmentAmount
      )
  
      val installment1 = Installment(
        id = 12L,
        debtId = debtId,
        recordId = 15L
      )
      val installment2 = Installment(
        id = 13L,
        debtId = debtId,
        recordId = 16L
      )
  
      val installments = listOf(
        WalletRecord(
          userId = debt.userId,
          type = RecordType.debt_rate,
          amount = installmentAmount,
          title = debt.title,
          category = RecordCategory.debt_rate,
          repeat = plan.interval,
          startDate = ZonedDateTime.parse(&quot;2021-11-28T00:00+01:00[Europe/Berlin]&quot;).toOffsetDateTime(),
          endDate = ZonedDateTime.parse(&quot;2021-12-27T00:00+01:00[Europe/Berlin]&quot;).toOffsetDateTime()
        ),
        WalletRecord(
          userId = debt.userId,
          type = RecordType.debt_rate,
          amount = installmentAmount,
          title = debt.title,
          category = RecordCategory.debt_rate,
          repeat = plan.interval,
          startDate = ZonedDateTime.parse(&quot;2021-12-28T00:00+01:00[Europe/Berlin]&quot;).toOffsetDateTime(),
          endDate = ZonedDateTime.parse(&quot;2022-01-27T00:00+01:00[Europe/Berlin]&quot;).toOffsetDateTime()
        )
      )
  
      every { user.tz } returns &quot;Europe/Berlin&quot;
      coEvery { debtRepository.findById(debtId) } returns debt
  
      //installment plan for debt with debtId exists
      coEvery { installmentPlanRepository.findByDebtId(debtId) } returns plan
  
      //update installment plan
      coEvery {
        installmentPlanRepository.save(planDTO.copy(amount = installmentAmount).toEntity(id = plan.id, debtId = debtId))
      } returns InstallmentPlan(plan.id, debtId, interval, firstPaymentDate, installmentAmount)
  
      //find and delete all previous installments/records for debt with debtId
      coEvery { installmentRepository.findByDebtId(debtId) } returns flowOf(installment1, installment2)
      coEvery { installmentRepository.deleteAllById(listOf(installment1.id!!, installment2.id!!)) } just Runs
      coEvery { recordService.deleteAll(listOf(installment1.recordId, installment2.recordId)) } just Runs
  
      //replace all new installments/records
      coEvery { userService.findById(debt.userId) } returns user
      coEvery { recordService.saveAll(installments) } returns flowOf()
      coEvery { installmentRepository.saveAll(any&lt;Flow&lt;Installment&gt;&gt;()) } returns flowOf()
  
      runBlocking { planService.storeInstallmentPlan(debtId, planDTO) }
  
      coVerify { installmentPlanRepository.save(
        planDTO.copy(amount = installmentAmount).toEntity(id = plan.id, debtId = debtId)
      ) }
      coVerify { recordService.saveAll(installments) }
      coVerify { installmentRepository.saveAll(any&lt;Flow&lt;Installment&gt;&gt;()) }
    }
  }
  
  </code></pre>