0

Arrow Kt Documentation on Dependency Injection中,依赖是在“世界边缘”定义的,或者在 Android 中可以是 anActivity或 a 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,我只需要定义一个不同的模块或手动将依赖项的值设置为一个模拟对象。

4

1 回答 1

3

在 Dagger 中,您将创建一个 Mock 或 Test 类,@Inject而不是ActivityApiService. 这里也一样。

代替:

class ActivityApiService(val ctx: Context) {
  fun createId(): String = doOtherThing(ctx)
}

你做

interface ActivityApiService {
  fun createId(): String
}

现在你有 2 个实现,一个用于 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 或类似工具来创建一个ActivityApiService.

我有几篇关于如何在与 Arrow 无关的 Android 框架之外解耦和统一的文章。检查“完全反应式应用程序中的无头开发”和相关项目https://github.com/pakoito/FunctionalAndroidReference

如果您的依赖关系图变得过于复杂,并且您想要一些编译时魔法来创建这些依赖关系,您总是可以在测试中创建一个本地类和@Inject那里的构造函数。关键是要从不可统一的事物中解耦出来,比如整个 Android 框架:D

于 2020-03-24T12:59:16.697 回答