1

I have a problem with MockK.

I have a class:

@Service
class ItemServiceImpl(private val varPuObjectMapper: VarPuObjectMapper) : OutboundAdvicesService {

    override suspend fun getItemsForWarehouse(warehouseId: String): ItemsDTO {
        // do stuff
    }

    override suspend fun getPickingListsForWarehouse(warehouseId: String): PickingListsDTO {
        val groupedOutboundAdvices = getItemsForWarehouse(warehouseId)
        // do other stuff
    }
}

and a test for this class:

class ItemServiceGroupingTest : FunSpec({

    val warehouseId = "1"
    val myObjectMapper = MyObjectMapper()
    val itemService = mockk<ItemServiceImpl>()

    beforeTest {
        val items1 = myObjectMapper
            .getObjectMapper()
            .readValue(Mockups.ITEMS_1, ItemsDTO::class.java)

        coEvery {
            itemService.getItemsForWarehouse(warehouseId)
        } returns items1
    }

    test("should get items for warehouse with ID 1") {
        val itemsDTO = itemService.getItemsForWarehouse(warehouseId)
        // assertions here
    }

    test("should get picking lists for warehouse with ID 1") {
        val pickingLists = itemService.getPickingListsForWarehouse(warehouseId)
        // assertions here
    }
})

Now the first test passes successfully, but the second one fails:

no answer found for: ItemServiceImpl(#1).getPickingListsForWarehouse(1, continuation {}) io.mockk.MockKException: no answer found for: ItemServiceImpl(#1).getPickingListsForWarehouse(1, continuation {}) at app//io.mockk.impl.stub.MockKStub.defaultAnswer(MockKStub.kt:93)

From what I understand, this fails cause the getPickingListsForWarehouse method is not mocked. Is it possible to call a real method using MockK? I tried to use spyk instead of mockk, and I tried mockk with relaxed = true, but it got me nowhere...

hc0re
  • 1,806
  • 2
  • 26
  • 61

1 Answers1

2

The problem with the second test is that you are trying to call a method from a mock without specified behavior. The first test passes because you already set the value which should be returned for the method call itemService.getItemsForWarehouse(warehouseId) in this statement in beforeTest:

        coEvery {
            itemService.getItemsForWarehouse(warehouseId)
        } returns items1

You have to do the same for getPickingListsForWarehouse or call a real method like:

every { itemService.getPickingListsForWarehouse(warehouseId) } answers { callOriginal() }

But then you have to use spyk instead of mock.

However, if you are asserting the object which you provided within the mock, you are not testing the real implementation of the method under test. You are just testing the mock, so if you change the implementation of your method this test still will be passing. beacuse it doesn't call your real object.

Karsten Gabriel
  • 3,115
  • 6
  • 19
Ice
  • 1,783
  • 4
  • 26
  • 52