Home > Enterprise >  Test case is calling actual method even after mocking the method call in ktor framework (kotlin)
Test case is calling actual method even after mocking the method call in ktor framework (kotlin)

Time:02-17

I am testing an API written in Kotlin using the KTOR framework. For the testing, I am using JUnit5 and Mockito. There is a route class where a route is defined which I need to test. Here is the route class :-

fun Application.configureRouting() {

    routing {
        post("/someRoute") {

            val service = MyService()
            val request: JsonNode = call.receive()

            launch {
                service.dummyFunction(request)
            }

            val mapper = ObjectMapper()
            val responseStr = "{\"status\":\"success\",\"message\":\"Request has been received successfully\"}"
            val response: JsonNode = mapper.readTree(responseStr)
            call.fireHttpResponse(HttpStatusCode.OK, response)

        }
    }
}

This is the test case I am writing for it :-

class RouteTest {

    @Mock
    var service = MyService()

    // read the configuration properties
    private val testEnv = createTestEnvironment {
        config = HoconApplicationConfig(ConfigFactory.load("application.conf"))
    }

    @Before
    fun setUp() = withApplication(testEnv) {
        MockitoAnnotations.openMocks(MyService::class)
    }

    @Test
    fun test() = withApplication(testEnv) {
        withTestApplication(Application::configureRouting) {
            runBlocking {
                Mockito.`when`(service.dummyFunction(Mockito.any()).thenReturn(true)

                with(handleRequest(HttpMethod.Post, "/someRoute") {
                    setBody("some body")
                }) {
                    assertEquals(HttpStatusCode.OK, response.status())
                }
            }
        }
    }
}

When I run the test, it calls the actual "dummyFunction()" method instead of the mocked one and hence, it is failing. Am I doing something wrong?

CodePudding user response:

Because your service in test is different from the service you mocked. To solve this, you need to inject the service into your class, or pass the service as an argument.

Read more: IoC, DI.

CodePudding user response:

The simplest way to solve your problem is to define the service parameter for the configureRouting method and pass a corresponding argument in the test and production code when calling it.

fun Application.configureRouting(service: MyService) {
    routing {
        post("/someRoute") {
            val request: JsonNode = call.receive()

            launch {
                service.dummyFunction(request)
            }

            val mapper = ObjectMapper()
            val responseStr = "{\"status\":\"success\",\"message\":\"Request has been received successfully\"}"
            val response: JsonNode = mapper.readTree(responseStr)
            call.fireHttpResponse(HttpStatusCode.OK, response)
        }
    }
}

class RouteTest {
    @Mock
    var service = MyService()

    private val testEnv = createTestEnvironment {
        config = HoconApplicationConfig(ConfigFactory.load("application.conf"))
    }

    @Test
    fun test() = withApplication(testEnv) {
        withTestApplication({ configureRouting(service) }) {
            runBlocking {
                // Your test...
            }
        }
  • Related