【问题标题】:Koin - how to provide mock ViewModel for espresso test?Koin - 如何为浓缩咖啡测试提供模拟 ViewModel?
【发布时间】:2018-10-16 17:42:27
【问题描述】:

我们如何将模拟的 viewModel 注入到 Activity 中进行 espresso 测试? 使用 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")))
    }
}

【问题讨论】:

    标签: android kotlin android-espresso android-viewmodel koin


    【解决方案1】:

    在这种情况下,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)))
        }
    }
    

    Sample code

    【讨论】:

    • 我收到了这个:Mockito cannot mock/spy because : - final class
    • @miladsalimi 我已经用@OpenForTesting 对其进行了注释。检查我分享的源代码。
    • 我如何使用这个注释?带有全开放编译器插件?
    • 是的,这可以解决问题@miladsalimi
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多