在Arrow Kt依赖项注入文档中,依赖项在"世界边缘"定义,或者在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
?由于依赖关系是在活动中创建的,因此不能再更改它进行测试?
当使用其他Dependency Injection
库时,此依赖项定义是在将要使用的类之外创建的。例如,在Dagger
中,创建一个Module
类来定义如何创建对象(依赖项(,并使用@Inject
来"注入"模块内部定义的依赖项。因此,现在在对Activity
进行单元测试时,我只需要定义一个不同的模块,或者手动将依赖项的值设置为mock对象。
在Dagger中,您将创建一个Mock或Test类,它将是@Inject
而不是ActivityApiService
。这里也是一样。
代替:
class ActivityApiService(val ctx: Context) {
fun createId(): String = doOtherThing(ctx)
}
你做
interface ActivityApiService {
fun createId(): String
}
现在有两个实现,一个用于prod
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或类似工具来创建CCD_ 12。
我有几篇关于如何在Android框架之外解耦和统一的文章,这些文章与Arrow无关。检查"全反应应用程序中的无头开发"和相关项目https://github.com/pakoito/FunctionalAndroidReference.
如果依赖关系图变得过于复杂,并且您想要一些编译时魔法来创建这些依赖关系,那么您总是可以在测试中创建一个本地类,并在那里创建@Inject
构造函数。重点是与不可统一的东西脱钩,比如整个Android框架:D