android - 如何在android Activity 测试中模拟koin注入(inject)的bean并捕获作为该模拟参数给出的lambda?

标签 android testing kotlin mocking koin

我花了很多时间寻找一种在 Android Activity 中模拟 Koin bean 的聪明方法。不幸的是,没有一个令人满意......直到 koin-1.0.0-alpha22 发布

谢谢@arnaudgiuliani。

可以在此处找到完整示例 AndroidTestKoin sample project

希望这有帮助 帕特里斯

最佳答案

此示例演示了如何在 androidTest 中使用 koin declareMock() 来捕获然后调用作为一个模拟 bean 参数给出的 lambda。

class CastManager() : ICastManager {
    private val devices = HashMap<String, Device>()

    init {
        devices["MyDevice"] = Device("MyDevice", "0000")
    }

    override fun getDevices(onSuccess: (List<Device>) -> Unit, onError: (Int) -> Unit){
        onSuccess(devices.values as List<Device>)
    }
}

主 Activity 在其 onCreate 中需要一个castManager 实例。

class MainActivity: AppCompatActivity() {

    private val castManager by inject<ICastManager>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)

        castManager.getDevices(
                        {devices: List<Device> -> onSuccess(devices)},
                        {error: Int -> onError(error)} )

        fab.setOnClickListener { view ->
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show()
        }
    }
...

真正的bean像往常一样声明......

val applicationModules = listOf(
        module {
            single() { CastManager() as ICastManager }
        }
)

并且 koin 由应用程序启动

open class MyApplication: Application() {

    override fun onCreate() {
        startKoin(this, applicationModules, logger = if (BuildConfig.DEBUG) AndroidLogger() else EmptyLogger())
        super.onCreate()
    }
}

从koin-1.0.0-alpha23开始,我们可以使用declareMock()来注入(inject)模拟实例

@RunWith(AndroidJUnit4::class)
class MainActivityTest: KoinTest {

    val myBeanToMock: ICastManager by inject()

    @Rule
    @JvmField
    //As interaction with mock starts in activity's onCreate we can't launch it before mock configuration
    val rule = object : ActivityTestRule<MainActivity>(MainActivity::class.java, false, false) {}

    @Before
    fun setUp() {
        loadKoinModules(applicationModules)
        declareMock<ICastManager>()
    }

    @After
    fun tearDown() {
        rule.finishActivity()
        closeKoin()
    }

    @Test
    fun verifyMockInjection() {
        // We want to capture lambda callbacks given as argument to the mock to interact with it's caller

        doAnswer {
            //arguments[0] is the onSuccess method
            @Suppress("UNCHECKED_CAST")
            (it.arguments[0] as (List<Device>) -> Unit).invoke(listOf(Device("myMockedDevice", "2000")))
        }.whenever(myBeanToMock).getDevices(any(), any())

        rule.launchActivity(null)
        BaristaVisibilityAssertions.assertDisplayed(R.string.my_mocked_device)
    }
}

Koin 1.0.0-alpha22版本中的createMock()被declareMock取代,以避免与Mockito的createMock冲突

关于android - 如何在android Activity 测试中模拟koin注入(inject)的bean并捕获作为该模拟参数给出的lambda?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51077209/

相关文章:

android - RxJava - 在 "subscribe"lambda 中使用不同类型的变量(多个链运算符的结果)

android - java.lang.ClassCastException : kotlinx. coroutines.CompletableDeferredImpl 无法转换为 java.util.List?

android - 在 Android 中使用默认字体样式

java - Android 上的 JNI : How to retrieve a string from Java code?

ASP.NET Web 应用程序测试经验

ios - iOS 6 状态保存和恢复的自动化测试

android - 我们如何使用 USER-AGENT 字符串来区分 1.笔记本电脑/台式机 2.IOS 3. Android 4.其他手机(BB、诺基亚、MS Mobile)

java - 如何在 Android Studio 中获取 Eclipse 风格的代码补全

string - 为什么要测试这些数字 (2^16, 2^31 ....)

android - RecyclerView中的 session 室数据库条目