Почему Mockito не может высмеивать общий тип параметра с типом номера в Kotlin?

Мы продвигаем наш проект на язык Котлин. Мы решили начать с тестов, но столкнулись с каким-то странным поведением.

Вот наш тестовый пример:

Service.java

public final class Service { private final JdbcTemplate jdbcTemplate; public Service(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public long check() { return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM table", Long.class); } } 

JavaTest.java (отлично работает)

 @RunWith(MockitoJUnitRunner.class) public final class JavaTest { @Mock private JdbcTemplate jdbcTemplate; @InjectMocks private Service testSubject; @Test public void test() { //given when(jdbcTemplate.queryForObject(anyString(), eq(Long.class))).thenReturn(1L); //when long result = testSubject.check(); //then assertThat(result, is(1L)); } } 

KotlinTest.kt (не работает)

 @RunWith(MockitoJUnitRunner::class) class KotlinTest { @Mock private lateinit var jdbcTemplate: JdbcTemplate @InjectMocks private lateinit var testSubject: Service @Test fun test() { //given `when`(jdbcTemplate.queryForObject(anyString(), eq(Long::class.java))).thenReturn(1L) //when val result = testSubject.check() //then assertThat(result, `is`(1L)) } } 

Тест Kotlin не работает с NullPointerException:

 java.lang.NullPointerException at ciService.check(Service.java:13) at ciKotlinTest.test(KotlinTest.kt:30) 

Кроме того, MockitoHint говорит:

 [MockitoHint] KotlinTest.test (see javadoc for MockitoHint): [MockitoHint] 1. Unused... -> at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:500) [MockitoHint] ...args ok? -> at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:500) 

Может ли кто-нибудь описать, что здесь происходит? Я совершенно новичок в Котлине и могу что-то пропустить.

Версия зависимостей: Kotlin 1.1.3-2, Mockito 2.7.19

Вместо этого используйте KClass # javaObjectType , например:

 // use java.lang.Long rather than long ---v `when`(jdbcTemplate.queryForObject(anyString(), eq(Long::class.javaObjectType))) .thenReturn(1L) 

Почему эта ошибка возникает?

Это потому, что Long::class.java возвращает примитивный тип long class, а не класс java.lang.Long . например:

 println(Long::class.java.name) // long println(Long::class.javaObjectType.name) // java.lang.Long println(Long::class.javaObjectType == Long::class.java) // ^--- false: thier class are different 

Согласованный параметр параметров метода [String, Class< long >] в тестовом коде Kotlin. когда mockito не может найти сопоставленный метод [String, Class< Long >] для издевательств в классе Java Service , тогда будет возвращено значение по умолчанию для getForObject метода mismatched getForObject , но возвращаемым типом метода getForObject является Object поэтому значение null возвращается по умолчанию.

Однако возвращаемый тип метода check long , и JVM пытается распаковать null в примитивный тип long в вашем классе Service тогда было NullPointerException , например:

 `when`(jdbcTemplate.queryForObject(anyString(), eq(Long::class.java))) .thenReturn(1L) assertEquals(1, jdbcTemplate.queryForObject("<any>", Long::class.java)) // ^--- matched: return 1 assertNull(jdbcTemplate.queryForObject("<any>", Long::class.javaObjectType)) // ^--- mismatched: return null testSubject.check() // ^--- throws NullPointerException 

Если вы замените тестовый код Java на long.class вы также получите ту же ошибку, например:

 // use long.class rather than Long.class ---v when(jdbcTemplate.queryForObject(anyString(), eq(long.class))).thenReturn(1L); // v--- matched: return 1L assertThat(jdbcTemplate.queryForObject("<any>", long.class), is(1L)); try { // v--- mismatched: return null long value = jdbcTemplate.queryForObject("<any>", Long.class); // ^--- throws NullPointerException when doing unboxing operation fail(); } catch (NullPointerException expected) { assertTrue(true); } 
Intereting Posts
Gradle не будет импортировать зависимость bintray, но не вызывает никакой ошибки Трансляционный приемник не получит намерения Ошибка проверки Котлина Предоставлять насмешливый объект другому конструктору конструктивного объекта? Kotlin: Идиоматический способ вызова (Int, Int) -> Int с парой <Int, Int>? Единичное тестирование Rxjava наблюдаемых, которые имеют задержку База данных Firebase всегда отключена, когда протестирована на физическом устройстве Android Невозможно использовать пользовательский getter с делегированным свойством Должен ли возврат DAO от Kotlin Необязательный или нулевой? Вызов «супер (прототип)» из Java на открытый класс данных Котлина DTO Смарт-бросок в BootsrapButton невозможен, потому что endtrip является изменчивым свойством, которое к этому времени изменилось Написание javascript-приложений с Kotlin notifyDataChanged () не удалось обновить данные расширяемого списка не случайное переопределение в Котлине Равенство в Котлине