Исключение Kotlin Mockito NullPointerException, возникающее при заглушении

#kotlin #mocking #mockito

#kotlin #издевательство #mockito

Вопрос:

Сегодня я наткнулся на ситуацию, которую я не понимаю, возможно, из-за отсутствия понимания того, как mockito и mockito-kotlin работают внутри.

Учитывая приведенный ниже код, с моей точки зрения новичка в Kotlin, у меня есть два довольно похожих интерфейсных метода. Один возвращает логическое значение, одну строку. В моем примере обе функции приостановлены, как и в моей реальной ситуации, мои функции тоже.

     class ITestInterface {
        suspend fun returnBoolean(): Boolean {
            return true
        }

        suspend fun returnSomeString() :  String {
            return "String"
        }
    }


    @Test
    fun demoTest() {
        val implMock = mock<ITestInterface> {
            on {
                runBlocking {
                    returnSomeString()
                }
            } doReturn "Hello"

            on {
                runBlocking {
                    returnBoolean()
                }
            } doReturn false
        }
    }
  

По моим наблюдениям, когда я запускаю тест, подобный изображенному выше, я получаю следующее сообщение об ошибке

 com.nhaarman.mockitokotlin2.MockitoKotlinException: NullPointerException thrown when stubbing.
This may be due to two reasons:
    - The method you're trying to stub threw an NPE: look at the stack trace below;
    - You're trying to stub a generic method: try `onGeneric` instead.

    at com.nhaarman.mockitokotlin2.KStubbing.on(KStubbing.kt:72)
    at com.rewedigital.fulfillment.picking.components.substitute.DemoTest.demoTest(DemoTest.kt:30)
  

[…]

Эксперименты показали, что

  • поведение только отображается логической функцией возврата, а не returnSomeString()
  • удаление ключевого слова suspend из функции returnBoolean устраняет ошибку
  • использование onGeneric, как предложено в сообщении об ошибке, также устраняет ошибку

Кто-нибудь может объяснить, почему это происходит? В какой степени мы должны здесь использовать дженерики? И каков был бы правильный способ решения проблемы в нашем реальном приложении? Наличие множества on {} и некоторого onGeneric {} ?

Спасибо за вашу помощь!

Ответ №1:

Вы должны использовать метод onBlocking, чтобы правильно имитировать функцию приостановки

Пожалуйста, попробуйте следующий код:

     @Test
    fun demoTest() {
        val implMock = mock<ITestInterface> {
            onBlocking {
                returnSomeString()
            } doReturn "Hello"

            onBlocking {
                returnBoolean()
            } doReturn false
        }

        runBlocking {
            // Execute your code here
            assertThat(implMock.returnSomeString()).isEqualTo("Hello")
            assertThat(implMock.returnBoolean()).isEqualTo(false)
        }
    }