Невозможно издеваться над конечным классом Kotlin с помощью Mockito 2

Я не могу издеваться над конечным классом Котлина, используя Mockito 2. Кроме того, я использую Robolectric.

Это мой тестовый код:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class Test {

    // more mocks

    @Mock
    MyKotlinLoader kotlinLoader;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }
}

тест терпит неудачу, когда мы пытаемся инициализировать насмешки в setUp() метод.

кроме того, я использую следующие зависимости gradle в своем коде:

testCompile 'org.robolectric:robolectric:3.3.2'
testCompile 'org.robolectric:shadows-multidex:3.3.2'
testCompile 'org.robolectric:shadows-support-v4:3.3.2'
testCompile("org.powermock:powermock-api-mockito2:1.7.0") {
    exclude module: 'hamcrest-core'
    exclude module: 'objenesis'
}
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-inline:2.8.9'

все другие модульные тесты проходят с помощью этой конфигурации, но как только я пытаюсь издеваться над классом Kotlin, он бросает следующее ошибка:

Mockito cannot mock/spy because : - final class

обратите внимание, что я использую Mockito версии 2, и я использую inline зависимость, которая автоматически дает возможность издеваться над конечными классами.

3 ответов


вы можете использовать Powermock для этого, например:

import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
@PrepareForTest({FinalClass1.class, FinalClass2.class})
public class Test {
    @Rule
    public PowerMockRule rule = new PowerMockRule();

    ... // your code here
}

PowerMock реализует свой собственный MockMaker что приводит к несовместимости с Mockito mock-maker-inline, даже если PowerMock просто добавляется как зависимость и не используется. Если два org.mockito.plugins.MockMaker существуют в пути, тогда можно использовать только один, который не определен.

PowerMock может, однако, делегировать вызовы другому MockMaker, а затем тесты запускаются без PowerMock. Начиная с PowerMock 1.7.0 это можно настроить с помощью конфигурации PowerMock.

В MockMaker можно настроить, создав файл org/powermock/extensions/configuration.properties и настройка:

mockito.mock-maker-class=mock-maker-inline

пример использования Mockito mock-maker-inline с PowerMock:https://github.com/powermock/powermock-examples-maven/tree/master/mockito2


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

import com.nhaarman.mockito_kotlin.mock
class MyFinalClass {...}
(snip)
private val MyFinalClass = mock()

Итак, давайте извлекем интерфейс:

class MyFinalClass : MyInterface {...}
(snip)
private val MyInterface = mock()