Я написал тестовые примеры для моей модели представления. Что, когда я запускаю индивидуально или когда я запускаю тестовый класс. Они успешно выполняются. Но когда я запускаю полный пакет androidTest, я получаю это исключение io.mockk.MockKException
Вот код, который успешно работает изолированно.
@RunWith(AndroidJUnit4::class)
class MyViewModelTest{
@Test
fun test_one(){
getInstrumentation().runOnMainSync(Runnable {
val context = ApplicationProvider.getApplicationContext<Context>()
mockkStatic(MyManager::class)
val myInterface = mockk<MyInterface>()
every { MyManager.getCommunicator() } returns myInterface
every { myInterface.context } returns context
every { myInterface.getLongFromGTM(any()) } returns 0
val viewModel = MyViewModel(context as Application)
viewModel.model = MyDataModel()
viewModel.model.isRepeatEligible = true
val res = viewModel.isRepeatEligible()
Truth.assertThat(res).isTrue()
})
}
}
Это ошибка, которую я получаю при запуске всего пакета androidTest:
Вот подробные используемые классы
1 .) MyManager.java
public class MyManager {
private static MyInterface myCommunicator;
public static MyInterface getCommunicator() {
if (myCommunicator == null) {
synchronized (MyManager.class) {
if (myCommunicator == null) {
Class<?> cls = Class.forName("mypackage.communicator.MyCommunicator");
myCommunicator = (MyInterface) cls.newInstance();
}
}
}
return myCommunicator;
}
}
2.) MyViewModel.kt
class MyViewModel(application: Application) : BaseViewModel(application) {
var model = MyDataModel()
private val timerDelay: Long by lazy {
myCommunicator.getLongFromGTM("key_p2m_timer_delay")
}
val timerDuration: Long by lazy {
myCommunicator.getLongFromGTM("key_p2m_timer_duration")
}
fun isRepeatEligible(): Boolean {
model.apply {
return isRepeatEligible && !isLinkBased && !isAlreadyPresent
}
}
У нас есть отдельный класс функций расширения, где у нас есть этот экземпляр myCommunicator, который создается следующим образом: «val myCommunicator: MyInterface = MyManager.getCommunicator()»
Это может быть (дополнительной) проблемой. Проверьте обновление в моем ответе.
Насмешка над чем-то с помощью MockK не ограничивается только одной функцией. В частности, когда вы имитируете объект с помощью mockkStatic
, с этого момента объект будет макетом, пока он не будет удален с помощью unmockkStatic
или unmockkAll
.
В вашем случае, я думаю, проблема возникает из-за статического насмешливого MyManager
, что позволяет последующим тестам не сработать, потому что они не ожидают, что объект будет смоделирован.
Это можно решить с помощью функции «после» (например, с помощью JUnit4, функции с аннотацией @After
), которая вызывает unmockAll
.
В качестве альтернативы, если вы хотите убедиться, что объект имитируется только локально, вы можете использовать вариант mockkStatic
, который принимает блок, который является единственным местом, где объект имитируется следующим образом:
mockkStatic(MyManager::class) {
// inside this block, MyManager is mocked
}
// MyManager is automatically unmocked after the block
Как упоминалось в вашем комментарии, вы не вызываете MyManager.getCommunicator()
напрямую в MyViewModel
, а через свойство расширения
val myCommunicator : MyInterface = MyManager.getCommunicator()
Это может привести к тому, что ваша тестовая установка останется на месте после теста, даже если вы разблокируете MyManager
, потому что свойство myCommunicator
сохранит свое значение — фиктивный интерфейс.
Это можно решить, изменив ваше свойство, чтобы оно не инициализировалось значением MyManager.getCommunicator()
, но вместо этого вы должны определить геттер, который вызывает MyManager.getCommunicator()
:
val myCommunicator: MyInterface get() = MyManager.getCommunicator()
Таким образом, вы всегда получаете текущее значение MyManager.getCommunicator()
, а не значение, которое было установлено один раз при инициализации.
См. https://kotlinlang.org/docs/properties.html#getters-and-setters для получения подробной информации о методах получения свойств.
Я попытался поместить код внутри этого блока mockkStatic, но все равно есть та же проблема.
Откуда
myCommunicator
вMyViewModel
? Это что-то определено вBaseViewModel
?