Простой класс kotlin с mockito-тестом вызвал MissingMethodInvocationException

Я начинаю изучать Kotlin и Mockito, поэтому я прописываю простой модуль для тестирования.

AccountData_K.kt:

open class AccountData_K { var isLogin: Boolean = false var userName: String? = null fun changeLogin() : Boolean { return !isLogin } } 

AccountDataMockTest_K.kt:

 class AccountDataMockTest_K { @Mock val accountData = AccountData_K() @Before fun setupAccountData() { MockitoAnnotations.initMocks(this) } @Test fun testNotNull() { assertNotNull(accountData) } @Test fun testIsLogin() { val result = accountData.changeLogin() assertEquals(result, true) } @Test fun testChangeLogin() { `when`(accountData.changeLogin()).thenReturn(false) val result = accountData.changeLogin() assertEquals(result, false) } } 

И когда я запускаю тест, он сообщает об исключении из testChangeLogin() :

 org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles); Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods *cannot* be stubbed/verified. 2. inside when() you don't call method on mock but on some other object. 3. the parent of the mocked class is not public. It is a limitation of the mock engine. at com.seal.materialdesignwithkotlin.AccountDataMockTest_K.testChangeLogin(AccountDataMockTest_K.kt:57) ... 

Я сомневаюсь, почему метод не является вызовом метода для макета …

Поэтому, пожалуйста, помогите мне, спасибо.

По умолчанию классы и члены Котлина являются окончательными . Мокито не может высмеять финальные классы и методы . Чтобы использовать Mockito, вам нужно open метод, который вы хотите высмеять:

 open fun changeLogin() : Boolean { return !isLogin } 

дальнейшее чтение

  • Можно ли использовать Mockito в Котлине?
  • Можно ли использовать Mockito с Kotlin без открытия класса?

PS. По моему скромному мнению, до тех пор, пока вы будете поддерживать небольшие интерфейсы, например, ISP , тестовый код, который использует Mockito или другую насмешливую структуру, редко читается и легко понимается, чем написанные вручную подделки / заглушки.

Как упоминает @miensol, ваша проблема возникает из-за того, что классы final по умолчанию в Котлине. Сообщение об ошибке не очень понятно, хотя эта часть упоминает final как одну из возможных причин:

  1. вы заглушите либо из методов final / private / equals () / hashCode ().

Существует проект, специально предназначенный для решения «финала по умолчанию» Котлина в модульном тестировании с помощью Mockito. Для JUNIT вы можете использовать kotlin-testrunner, который является простым способом сделать любой тест Kotlin автоматически открывать классы для тестирования, поскольку они загружаются загрузчиком классов. Использование простое, просто добавьте одну аннотацию @RunWith(KotlinTestRunner::class) , например:

 @RunWith(KotlinTestRunner::class) class MyKotlinTestclass { @Test fun test() { ... } } 

Это подробно освещено в статье. Никогда не говорите финала: насмешливые классы Котлина в модульных тестах

Это автоматически охватывает ваш прецедент, позволяя всем классам высмеиваться, что в противном случае было бы запрещено.