如何在 android activity 测试中模拟 koin 注入的 bean 并捕获作为此模拟参数给出的 lambda?
How to mock a koin injected bean in android activity test and capture lambda given as parameter of this mock?
我花了很多时间在 android activity 中找到了一种模拟 Koin bean 的聪明方法。不幸的是 none 令人满意......直到 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() 注入模拟实例
@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 activity 中找到了一种模拟 Koin bean 的聪明方法。不幸的是 none 令人满意......直到 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() 注入模拟实例
@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 冲突