Как мы можем внедрить имитацию viewModel в Activity для теста эспрессо?
Используя declareMock, я получаю фиктивный объект в классе Test, но Activity получает обычный объект viewModel.
@RunWith(AndroidJUnit4::class)
class SomeActivityTest : KoinTest {
@Rule
@JvmField
val rule = ActivityTestRule(SomeActivity::class.java, true, true)
val viewModel: MyViewModel by inject()
@Before
fun setup() {
declareMock<MyViewModel>(isFactory = true, binds = listOf(ViewModel::class))
}
@After
fun cleanUp() {
stopKoin()
}
@Test
fun shouldHaveTextViewVisible() {
`when`(viewModel.sayHello())
.thenReturn("hello view-model")
onView(withId(R.id.tv_homescreen_message))
.check(matches(isDisplayed()))
onView(withId(R.id.tv_homescreen_message))
.check(matches(withText("hello view-model")))
}
}
В этом случае тест Espresso все еще использовал основной класс приложения, который объявляет все модули koin, необходимые для приложения.
Запуск koin без каких-либо модулей позволяет нам во время теста загружать только необходимые модули.
// application class for espresso tests
class TestApp : Application() {
override fun onCreate() {
super.onCreate()
startKoin(this, emptyList())
}
}
class TestAppJUnitRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application {
return super.newApplication(cl, TestApp::class.java.name, context)
}
}
// app module build.gradle
android {
defaultConfig {
testInstrumentationRunner "com.package.TestAppJUnitRunner"
}
}
Перед началом деятельности важно объявить фиктивный метод.
@RunWith(AndroidJUnit4::class)
class SomeActivityTest : KoinTest {
@Rule
@JvmField
val rule = ActivityTestRule(SomeActivity::class.java, true, false)
lateinit var mockVm: MyViewModel
@Before
fun setup() {
mockVm = mock(MyViewModel::class.java)
loadKoinModules(module {
viewModel {
mockVm
}
})
}
@After
fun cleanUp() {
stopKoin()
}
@Test
fun shouldHaveTextViewWithMessage() {
// 1. declare mock method
val message = "hello view-model"
Mockito.`when`(mockVm.sayHello())
.thenReturn(message)
// 2. start activity
rule.launchActivity(null)
// 3. test
onView(withId(R.id.tv_message))
.check(matches(isDisplayed()))
onView(withId(R.id.tv_message))
.check(matches(withText(message)))
}
}