Arrow KT 上的依赖注入
Dependency Injection on Arrow KT
在 Arrow Kt Documentation on Dependency Injection 中,依赖项在 "Edge of the World" 或 Android 中定义,可以是 Activity
或 Fragment
。所以给定的例子如下:
import Api.*
class SettingsActivity: Activity {
val deps = FetcherDependencies(Either.monadError(), ActivityApiService(this))
override fun onResume() {
val id = deps.createId("1234")
user.text =
id.fix().map { it.toString() }.getOrElse { "" }
friends.text =
deps.getUserFriends(id).fix().getOrElse { emptyList() }.joinToString()
}
}
但是现在我在想例子中的SettingsActivity
怎么会是unit tested
呢?由于依赖项是在 activity 中创建的,因此无法再更改以进行测试?
当使用其他一些 Dependency Injection
库时,此依赖项定义是在将要使用的 class 之外创建的。例如在 Dagger
中,创建 Module
class 来定义对象(依赖项)的创建方式,并使用 @Inject
来 "inject" 定义的依赖项在模块内部。所以现在当对 Activity
进行单元测试时,我只需要定义一个不同的模块或手动将依赖项的值设置为模拟对象。
在 Dagger 中,您将创建一个模拟或测试 class,您将 @Inject
而不是 ActivityApiService
。这里也是一样。
而不是:
class ActivityApiService(val ctx: Context) {
fun createId(): String = doOtherThing(ctx)
}
你会
interface ActivityApiService {
fun createId(): String
}
现在您有 2 个实现,一个用于产品
class ActivityApiServiceImpl(val ctx: Context): ActivityApiService {
override fun createId(): Unit = doOtherThing(ctx)
}
还有一个用于测试
fun testBla() {
val api = object: ActivityApiService {
override fun createId(): String = "4321"
}
val deps = FetcherDependencies(Either.monadError(), api)
deps.createId("1234") shouldBe "4321"
}
甚至使用 Mockito 或类似工具来创建 ActivityApiService
。
我有几篇关于如何在 Android 框架之外进行解耦和联合测试的文章,这些文章与 Arrow 无关。检查 'Headless development in Fully Reactive Apps' and the related project https://github.com/pakoito/FunctionalAndroidReference.
如果您的依赖关系图变得过于复杂,并且您想要一些编译时魔法来创建这些依赖关系,您始终可以在测试中创建一个本地 class 并在那里创建 @Inject
构造函数。关键是要与不可测试的事物分离,比如整个 Android 框架 :D
在 Arrow Kt Documentation on Dependency Injection 中,依赖项在 "Edge of the World" 或 Android 中定义,可以是 Activity
或 Fragment
。所以给定的例子如下:
import Api.*
class SettingsActivity: Activity {
val deps = FetcherDependencies(Either.monadError(), ActivityApiService(this))
override fun onResume() {
val id = deps.createId("1234")
user.text =
id.fix().map { it.toString() }.getOrElse { "" }
friends.text =
deps.getUserFriends(id).fix().getOrElse { emptyList() }.joinToString()
}
}
但是现在我在想例子中的SettingsActivity
怎么会是unit tested
呢?由于依赖项是在 activity 中创建的,因此无法再更改以进行测试?
当使用其他一些 Dependency Injection
库时,此依赖项定义是在将要使用的 class 之外创建的。例如在 Dagger
中,创建 Module
class 来定义对象(依赖项)的创建方式,并使用 @Inject
来 "inject" 定义的依赖项在模块内部。所以现在当对 Activity
进行单元测试时,我只需要定义一个不同的模块或手动将依赖项的值设置为模拟对象。
在 Dagger 中,您将创建一个模拟或测试 class,您将 @Inject
而不是 ActivityApiService
。这里也是一样。
而不是:
class ActivityApiService(val ctx: Context) {
fun createId(): String = doOtherThing(ctx)
}
你会
interface ActivityApiService {
fun createId(): String
}
现在您有 2 个实现,一个用于产品
class ActivityApiServiceImpl(val ctx: Context): ActivityApiService {
override fun createId(): Unit = doOtherThing(ctx)
}
还有一个用于测试
fun testBla() {
val api = object: ActivityApiService {
override fun createId(): String = "4321"
}
val deps = FetcherDependencies(Either.monadError(), api)
deps.createId("1234") shouldBe "4321"
}
甚至使用 Mockito 或类似工具来创建 ActivityApiService
。
我有几篇关于如何在 Android 框架之外进行解耦和联合测试的文章,这些文章与 Arrow 无关。检查 'Headless development in Fully Reactive Apps' and the related project https://github.com/pakoito/FunctionalAndroidReference.
如果您的依赖关系图变得过于复杂,并且您想要一些编译时魔法来创建这些依赖关系,您始终可以在测试中创建一个本地 class 并在那里创建 @Inject
构造函数。关键是要与不可测试的事物分离,比如整个 Android 框架 :D